C# , How to output specific array searches? - c#

The program I am creating prompts the user to enter an amount of months, the amount of work absences he/she has had in each month, and the amount of absences allowed per month. It is supposed to calculate the average amount of work absences by an employee as well as the amount of times that he/she went over the max absences allowed.
I was able to calculate the average with an array loop but was having issues with the times he/she has gone over the max absences. I am using the binary search method but have trouble outputting the specific amount of months that the employee has gone over the allowed absence amount.
This is my current code for that section:
for (int i = 0; i < numbOfAbsences.Length; i++)
{
sum += numbOfAbsences[i];
averageAbsences = (sum / numbOfMonths);
Console.WriteLine("Employee was absent " + averageAbsences + " times per month.");
}
a = Array.BinarySearch(numbOfAbsences, maxAbsences);
if (a >= maxAbsences)
{
}
I am unsure of what would go under the last set of brackets, as I am not trying to point out whether the max amount was exceeded but rather the amount of times that it was.
Thank you for the help in advanced.

First off, the question is not clearly stated. It boils down to this:
"What's a good way to take an int array of sums and divide them all by a count to produce a double array of averages? Also, how can I count the values of an int array greater than a threshold? (Here's what I've got so far: )"
Second, the code snippet is very confusing. More precisely... It's not indented correctly. Not all of the variables used are defined, so we have to guess what they are. The variable names aren't very descriptive, so one has to look at how each variable is used to understand it. Most importantly however, this is no encapsulation. No objects, no functions... just raw code that you need to read every line of very carefully to understand.
Contrast the snippet with this:
using System;
using System.Linq;
namespace ArraySearch_StackOverflow
{
class Program
{
static void Main(string[] args)
{
int[] employeeAbsencesEachMonth = new int[] { 1, 2, 3, 4, 5, 6 };
int maxAbsencesAllowedPerMonth = 3;
double averageAbsencesPerMonth = GetAverageAbsencesPerMonth(employeeAbsencesEachMonth);
Console.WriteLine($"Employee's Average Absences Per Month: {averageAbsencesPerMonth}"); /* 3 */
int numTimesMaxAbsencesExceeded = GetNumMaxAbsencesViolations(employeeAbsencesEachMonth, maxAbsencesAllowedPerMonth);
Console.WriteLine($"Number of Times Employee Exceeded Max Absence Limit: {numTimesMaxAbsencesExceeded}"); /* 3 */
Console.WriteLine("\nPress any key to continue...");
Console.ReadKey();
}
private static double GetAverageAbsencesPerMonth(int[] employeeAbsencesEachMonth)
{
// ???
throw new NotImplementedException();
}
private static int GetNumMaxAbsencesViolations(int[] employeeAbsencesEachMonth, int maxAbsencesAllowedPerMonth)
{
// ???
throw new NotImplementedException();
}
}
}
This snippet is extremely clear. Even without a description, it's immediately apparent what's being asked, and how to tell if an answer is correct. Because the questions have been translated into a function signature and the context has been translated into a driver in which the functions are called, complete with setup and an expected result.
Handily, this implies a simple format for the answer, creating a good chance you can copy-paste it directly into your code:
private static double GetAverageAbsencesPerMonth(int[] employeeAbsencesEachMonth)
{
return employeeAbsencesEachMonth.Sum() / employeeAbsencesEachMonth.Length;
}
private static int GetNumMaxAbsencesViolations(int[] employeeAbsencesEachMonth, int maxAbsencesAllowedPerMonth)
{
return employeeAbsencesEachMonth.Count(x => x > maxAbsencesAllowedPerMonth);
}

Related

How can I use a Lambda Expression to calculate a function in C# with variables from multiple nodes in a LinkedList<object>?i

static void Main(string[] args)
{
LinkedList<Day> Days = new LinkedList<Day>();
Day day1 = new Day() { sunUp = 800, sunDown = 1800 };
Day day2 = new Day() { sunUp = 755, sunDown = 1805 };
Day day3 = new Day() { sunUp = 750, sunDown = 1810 };
Day day4 = new Day() { sunUp = 745, sunDown = 1815 };
Day day5 = new Day() { sunUp = 740, sunDown = 1820 };
Days.AddLast(day1);
Days.AddLast(day2);
Days.AddLast(day3);
Days.AddLast(day4);
Days.AddLast(day5);
Console.WriteLine("There is an average of {0} minutes of night over the past {1} days.", Calculator(Days), Days.Count);
}
public static int ToMinutes(int time)
{
return time / 100 * 60 + time - time / 100 * 100;
}
class Day
{
public int sunUp;
public int sunDown;
}
public static int Calculator(LinkedList<Day> Days)
{
var current = Days.First;
int nightDuration = 0;
int count = 0;
while (current.Next != null)
{
nightDuration += ToMinutes(current.Value.sunDown) - ToMinutes(current.Next.Value.sunUp);
current = current.Next;
count++;
}
return nightDuration/count;
}
Requirement: Day must be stored in a LinkedList.
Is there a clean Lambda Expression equivalent to the Calculator method above? I am having trouble using Lambda's to calculate a function with variables across connected nodes.
Thanks for the help!
Cheers,
Kyle
Quite a few things are wrong with your pseudo code of using a calculator (for addition in this instance)
You have a class that has two integers. I believe your idea is to add the two numbers together along with two numbers from every other node of the linked list. But, you are adding only the first number from Pair and adding it to 2nd number of the next node... dont think it will work.
array = current.value.int1 + current.Next.value.int2;
should be
array = current.value.int1 + current.value.int2;
Working Example
public static int Calculator(LinkedList<Pair> Pairs)
{
var current = Pairs.First;
int sum = 0;
while (current != null)
{
sum += current.Value.num1 + current.Value.num2;
current = current.Next;
}
return sum;
}
Ran this in the main,
LinkedList<Pair> Pairs = new LinkedList<Pair>();
Pair pair = new Pair() { num1 = 1, num2 = 5 };
Pairs.AddFirst(pair);
Pairs.AddLast(pair);
Pairs.AddLast(pair);
Console.WriteLine( Calculator(Pairs));
Output
18
Lambda expression you can use to add up all the linked lists can be summed up as,
Console.WriteLine(Pairs.Sum(x => x.num1 + x.num2));
Output
18
Hope it helps
Looking at your example i see what you're trying to say. So you want to the same logic as in your Calculator method but using Lambda expression. The most easy way to do this is to use Language Integrated Query (LINQ).
So breaking up your Calculator() method we see it actually contains 2 elements.
Sum up each value after you've combined num1 with num2 in the List
Divide the end result with the total count in the list.
The most easy way to do this is by using Enumerable.Sum and then devide that value by the count of the list. For example:
Pairs.Sum(pair => pair.num1 + pair.num2) / Pairs.Count
Result: 6
Here a code example
Enumerable.Sum is extension method from System.Linq namespace. It returns sum of numeric values in collection.
Although Lambda expressions are awesome, please do bare in mind that readability is also very important. They are basically anonymous functions which, if the logic gets complex, will be hard to understand for other developers/team members.
Hope this helps. Good luck!
EDIT
So if i understand it correctly you're having a hard time using lambda expressions with nested methods. Like for example your Calculator() method makes use of another method ToMinutes.
Using the code from my first example, we can still use the logic. The most important part we have to change is the logic within the Sum. E.g.
Days.Sum(day => ToMinutes(day.sunDown) - ToMinutes(day.sunUp )) / totalDays;
This is just one of the ways to do it. Another option is to create an ExtensionMethod. E.g.
namespace ExtensionMethods
{
public static class IntExtensions
{
public static int ToMinutes(this int time)
{
return time / 100 * 60 + time - time / 100 * 100;
}
}
}
Above the class you want to use the extension method just include it by writing
using ExtensionMethods;
at the top of your document.
This will give another option to all your integers to parse the value to a different value. In our case, to minutes.
int totalDays = Days.Count;
int averageMinutes = Days.Sum(day => day.sunDown.ToMinutes() - day.sunUp.ToMinutes()) / totalDays;
Console.WriteLine("There is an average of {0} minutes of night over the past {1} days.", averageMinutes, totalDays);
But again. This is one of the ways of doing it. I would recommend you to get and read C# in Depth by Jon Skeet and also dive into the clean code principles.
Anyways, i think i have made myself clear. See example code for more details.
Good luck!

Generating a variable number of random numbers to a list, then comparing those numbers to a target?

How would I go about generating a serializable variable of random numbers to a list, then comparing those generated numbers to a target number?
What I want to do is make a program that takes in a number, such as 42, and generates that number of random numbers to a list while still keeping the original variable, in this case 42, to be referenced later. Super ham-handed pseudo-code(?) example:
public class Generate {
[SerializeField]
int generate = 42;
List<int> results = new List<int>;
public void Example() {
int useGenerate = generate;
//Incoming pseudo-code (rather, code that I don't know how to do, exactly)
while (useGenerate => 1) {
results.add (random.range(0,100)); //Does this make a number between 0 and 99?
int useGenerate = useGenerate - 1;
}
}
}
I think this will do something to that effect, once I figure out how to actually code it properly (Still learning).
From there, I'd like to compare the list of results to a target number, to see how many of them pass a certain threshold, in this case greater than or equal to 50. I assume this would require a "foreach" thingamabobber, but I'm not sure how to go about doing that, really. With each "success", I'd like to increment a variable to be returned at a later point. I guess something like this:
int success = 50;
int target = 0;
foreach int in List<results> {
if (int => success) {
int target = target + 1;
}
}
If I have the right idea, please just teach me how to properly code it. If you have any suggestions on how to improve it (like the whole ++ and -- thing I see here and there but don't know how to use), please teach me that, too. I looked around the web for using foreach with lists and it seemed really complicated and people were seemingly pulling some new bit of information from the Aether to include in the operation. Thanks for reading, and thanks in advance for any advice!

Unity formatting multiple numbers

So I'm a complete newb to unity and c# and I'm trying to make my first mobile incremental game. I know how to format a variable from (e.g.) 1000 >>> 1k however I have several variables that can go up to decillion+ so I imagine having to check every variable's value seperately up to decillion+ will be quite inefficient. Being a newb I'm not sure how to go about it, maybe a for loop or something?
EDIT: I'm checking if x is greater than a certain value. For example if it's greater than 1,000, display 1k. If it's greater than 1,000,000, display 1m...etc etc
This is my current code for checking if x is greater than 1000 however I don't think copy pasting this against other values would be very efficient;
if (totalCash > 1000)
{
totalCashk = totalCash / 1000;
totalCashTxt.text = "$" + totalCashk.ToString("F1") + "k";
}
So, I agree that copying code is not efficient. That's why people invented functions!
How about simply wrapping your formatting into function, eg. named prettyCurrency?
So you can simply write:
totalCashTxt.text = prettyCurrency(totalCashk);
Also, instead of writing ton of ifs you can handle this case with logarithm with base of 10 to determine number of digits. Example in pure C# below:
using System.IO;
using System;
class Program
{
// Very simple example, gonna throw exception for numbers bigger than 10^12
static readonly string[] suffixes = {"", "k", "M", "G"};
static string prettyCurrency(long cash, string prefix="$")
{
int k;
if(cash == 0)
k = 0; // log10 of 0 is not valid
else
k = (int)(Math.Log10(cash) / 3); // get number of digits and divide by 3
var dividor = Math.Pow(10,k*3); // actual number we print
var text = prefix + (cash/dividor).ToString("F1") + suffixes[k];
return text;
}
static void Main()
{
Console.WriteLine(prettyCurrency(0));
Console.WriteLine(prettyCurrency(333));
Console.WriteLine(prettyCurrency(3145));
Console.WriteLine(prettyCurrency(314512455));
Console.WriteLine(prettyCurrency(31451242545));
}
}
OUTPUT:
$0.0
$333.0
$3.1k
$314.5M
$31.5G
Also, you might think about introducing a new type, which implements this function as its ToString() overload.
EDIT:
I forgot about 0 in input, now it is fixed. And indeed, as #Draco18s said in his comment nor int nor long will handle really big numbers, so you can either use external library like BigInteger or switch to double which will lose his precision when numbers becomes bigger and bigger. (e.g. 1000000000000000.0 + 1 might be equal to 1000000000000000.0). If you choose the latter you should change my function to handle numbers in range (0.0,1.0), for which log10 is negative.

Random.Next() How many iterations before a wrap around occurs?

I'm pretty sure that this will never be an issue. However, I'm still curious, exactly how many iterations can any given seed generate a random number before its scope is fully exhausted and it wraps back around to generating the same numbers again?
As an example:
Suppose you have an array consisting of eight integer indices; during a given iteration the random.Next would fill each indice with a value of 0-31. And the test is attempting to see how long it would take to generate a perfect array of all 31's.
Mathematically, the odds are roughly 1 in 1,099,511,627,776 per iteration to yield a perfect array of all 31's. However, this is assuming that the C# Random number generator could even make it to the projected range of 1 trillion iterations without wrapping back around on itself.
So, to sum up my actual question, could the Random class achieve the test that I have presented? Or would it reach a half-way mark and just doom itself to failure regardless of how many iterations it goes through? What exactly is the number of iterations before the end of the random number generator will be reached? I wanted to also mention that it only takes about 20 minutes to successfully generate an array of 6 perfect 31's. This was tested by me and verified.
I should also mention that I am currently running a testing mechanism that is trying to achieve this. So far, this is the current report, which is displayed every minute:
##### Report #####
Elapsed Simulation Time: 00:49:00.1759559
Total Iterations: 20784834152
Perfect Eight Success: 0
Failure: 20784834152
##### End Report #####
I have estimated the required time to find 1 perfect array of 31's to be roughly 47 Hours and 56 Minutes to get close to the range of finding even 1 perfect set of 31's. That's with my computer filling my array 383,500,572 every minute. Looks like this test will take far longer than I originally projected.
2 Hour Update
##### Report #####
Elapsed Simulation Time: 02:00:00.4483950
Total Iterations: 55655726300
Success: 0
Failure: 55655726300
##### End Report #####
I kind of wish I would have threaded this...probably could have cut the time in half...
Enough comments already. Here's the definitive answer.
First: The RNG can, at best, operate on 64-bit values. There are finitely many 64-bit values, so, according to the pigeonhole principle, with enough iterations (n > 2^64) you will definitely get at least one repetitive value.
The underlying algorithm uses some finite, arbitrary number of parameters to decide the next random value. If we assume there are N state variables, each with 64 bits, there can be at most (2^64)^N different internal states. Like before, with enough iterations, your RNG will have the same internal state. This will cause a loop, and it will certainly come to pass at some point in time. As for how many iterations it takes to loop back, suffice it to say there will be more than you'll ever need for day-to-day random number generation. I haven't run into any such loop yet (it's been generating for 20 minutes straight on my i7 CPU, and if your code generates that many numbers, you're probably doing something very wrong).
Second: I don't know about eight 31's in a row, but that's just a special case. What you're asking, basically, is this: Given some arbitrary sequence S_QUERY of numbers, will the RNG generate S_QUERY?
To answer, we must first note that the RNG generates a finite sequence S_RNG of numbers. So the real question is this: is S_QUERY a subsequence of S_RNG? Since S_RNG is finite, it can only have finitely many subsequences. However, there are infinitely many possible S_QUERY's to choose from, so for every RNG you can find some S_QUERY's which cannot be generated by that RNG. As for the special case of eight 31's, I don't know and I can't know. Keep that code running and find out.
I just wanted to post my testing code and explain a few things. First, here is my code:
using System;
using System.Diagnostics;
namespace ConsoleApplication1
{
public static class Program
{
public static long Success;
public static long Failure;
public static long TotalIterations;
public static long TotalCallsToRandom;
public static readonly int CurrentSeed = Environment.TickCount;
public static Random Random = new Random(CurrentSeed);
public static Stopwatch TotalSimulationTime = new Stopwatch();
public static Stopwatch ReportWatchTime = new Stopwatch();
public static bool IsRunning = true;
//
public const int TotalTestingIndices = 7;
public const int MaximumTestingValue = 31;
public const int TimeBetweenReports = 30000; // Report every 30 Seconds.
//
public static void Main(string[] args)
{
int[] array = new int[TotalTestingIndices];
TotalSimulationTime.Start();
ReportWatchTime.Start();
while (IsRunning)
{
if (ReportWatchTime.ElapsedMilliseconds >= TimeBetweenReports)
{
Report();
ReportWatchTime.Restart();
}
Fill(array);
if (IsPerfect(array))
{
Success++;
Console.WriteLine("A Perfect Array was found!");
PrintArray(array);
Report();
IsRunning = false;
}
else
{
Failure++;
}
TotalIterations++;
}
Console.Read();
}
public static void Report()
{
Console.WriteLine();
Console.WriteLine("## Report ##");
Console.WriteLine("Current Seed: " + CurrentSeed);
Console.WriteLine("Desired Perfect Number: " + MaximumTestingValue);
Console.WriteLine("Total Testing Indices: " + TotalTestingIndices);
Console.WriteLine("Total Simulation Time: " + TotalSimulationTime.Elapsed);
Console.WriteLine("Total Iterations: " + TotalIterations);
Console.WriteLine("Total Random.NextInt() Calls: " + TotalCallsToRandom);
Console.WriteLine("Success: " + Success);
Console.WriteLine("Failure: " + Failure);
Console.WriteLine("## End of Report ##");
Console.WriteLine();
}
public static void PrintArray(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
Console.Write(array[i]);
if (i != array.Length - 1)
{
Console.Write(",");
}
}
}
/// <summary>
/// Optimized to terminate quickly.
/// </summary>
/// <param name="array"></param>
/// <returns></returns>
public static bool IsPerfect(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (array[i] != MaximumTestingValue)
{
return false;
}
}
return true;
}
public static void Fill(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = Random.Next(MaximumTestingValue + 1);
TotalCallsToRandom++;
}
}
}
}
After about three hours of testing I have come to a few realizations. I believe it may be possible to get eight perfect indices of 31...but only if you get lucky within the first billion or so calls to Random.Next(). I know this may seem like a subjective thing to say, but it's what I have experienced through these tests. I never once got 8-Perfect 31's, but I did get 7-Perfect 31's. The first time it was after 13 minutes. Here is the print out:
A Perfect Array was found!
31,31,31,31,31,31,31
## Report ##
Total Simulation Time: 00:13:32.4293323
Total Iterations: 7179003125
Success: 1
Failure: 7179003125
## End of Report ##
I didnt have it coded in at the time to print it out, but that print out would mean there were 50,253,021,875 individual calls to Random.NextInt(); This means that the resolution held up all the way to 50 Billion calls.
And the other 7-Perfect was only after about 30 seconds of the program running. That means there are "Good Seeds" for getting this kind of rarity fairly quickly. I also ran the test for 7-Perfect indices for thirty minutes and didn't get a single one. It's based on luck, but at the same time I heavily feel as though there is an invisible threshold; if you don't hit it soon it won't happen at all. A poster above said that the resolution of the Random class is "281,474,976,710,656". But my tests seem to conclude that the resolution may actually be far smaller than that. Try it yourself, start from 4-6 indices(Happens within a matter of seconds) and move up to 7 and 8. It's not just that the probability increases, it's that there is a threshold...or maybe I am just wrong. Who knows?

Decaying value over time expontentially

I want to create a sorting algorithm that takes an items score (based on upvotes/downvotes) and sorts them based on an invisble underlying score that take time decay into account.
Being from the analytic philosophy side, my mathematical algorithms aren't always the best. What is a simple elegant way to solve for InverseTimeRelationship(currentItem.CreationDate) in the following example:
class Item()
{
int upvotes;
int downvotes;
int SortScore;
DateTime CreationDate;
}
var currentItem = GetSomeSpecificItemMethod();
int Score = currentItem.upvotes - currentItem.downvotes;
currentItem.SortScore = Score * InverseTimeRelationship(currentItem.CreationDate);
SortItemsBySortScore(Item[]);
InverseTimeRelationship(DateTime CreationDate)
{
//Code To Write
}
The hope being that after a day, the SortScore would be a little lower, but after say 2-3 days no matter how many votes it has, it will disappear from the top of the list/front page.
You can take a look at the algorithm reddit uses. It seems to be what you want.
Perhaps:
e^-x (= 1/e^x)
See this image (from Wikipedia).
And here's code:
double InverseTimeRelationship(DateTime CreationDate)
{
double HowFast = 0.1;
return Math.Exp(-DateTime.Now.Subtract(CreationDate).Days * HowFast);
}
And you can try it with:
Text = InverseTimeRelationship(DateTime.Today.AddDays(-3)).ToString();

Categories