Generate 30 Random Numbers from a given sum - c#

I am working on a report in C# in which I am given a total number of prints a department printed and I have to distribute them according to the month date that on 1st March 10 papers are printed out and so on to 31st March.
I have a form which takes the total print outs count.
I have a Month Selector.
From Month I get the total days which is total numbers to be generated eg: 30 or 31 or 28
Scenario :
In the month of March 2000 Prints outs
Total Sum of Month : 2000
Numbers to be generated : 31
this is my code
int sum = 2345;
int nums = 23;
Random rand = new Random();
int newNum = 0;
int[] ar = new int[23];
for (int i = 0; i < nums; i++)
{
newNum = rand.Next(0, sum);
ar[i] = newNum;
sum = sum - newNum;
}
for (int i = 0; i < 23 ; i++)
{
Console.WriteLine(ar[i]);
}
Console.ReadLine();
what happens is in the ending numbers it goes to zero . I want Normally distributed like on one index it stores the maximum value at first and in the end it decreases.
We have a thrid party Ricoh Print/PhotoCopier Machine installed and third party bills us with certain amount which they have calculate that our department has printed 3000 printouts so we have to distribute them in the days randomly, print out the report and get payment invoice from our department head.
The department people are doing it on excel I offered them to give them a solution. Windows form application is built and I just have to put this logic thats all..
Thank you for your feedbacks

You can do this easily with partitions. For a 4 day month that produced 10 things: generate 3 random numbers between 0 and 10 (inclusive). Sort them and append 10 to the list of numbers. So we have perhaps:
3 6 6 10
Which partitions our prints:
p p p | p p p | | p p p p

If you want to have 23 random numbers with sum of 2345, you can use this code:
int sum = 2345;
int nums = 23;
int max = sum / nums;
Random rand = new Random();
int newNum = 0;
int[] ar = new int[23];
for (int i = 0; i < nums-1; i++) {
newNum = rand.Next(max);
ar[i] = newNum;
sum-= newNum;
max = sum / (nums-i-1);
}
ar[nums - 1] = sum;
It will give you:

Here is my idea for generating 30 random numbers with a specific sum:
int sum = 3000;
int size = 30; // assumes that (sum % size == 0)
int[] result = new int[size];
Random rand = new Random();
int x = sum / size;
for (int i = 0; i < size; i++)
{
result[i] = x;
}
for (int i = 0; i < x; i++)
{
var a = rand.Next(size - 1); // not sure if parameter is inclusive?
var b = rand.Next(size - 1); // should return number between 0 and size-1 inclusively
result[a]++;
result[b]--;
}
int testSum = result.Sum(); // will equal "sum" (3000)
Lee Daniel Crocker linked to this, though, which I think is a better solution. Very neat and intuitive.

Related

How exactly does one make random numbers add up to a declared sum?

I'm confused as to how exactly I would make 9 random numbers add to whatever number the user may input. Let's say the user inputs "200" as the number, how do I make it so that I could get 9 random numbers add up exactly to 200?
Obviously, the code below doesn't work the way I want it to because it's literally just 9 random numbers that don't add up to a specific number. I just have no idea how to get this built properly.
public static void RandomStats()
{
Random RandomClass = new Random();
int[] intRandomStats = {
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101),
RandomClass.Next(0, 101)
};
// ...
}
I think your question is more of math question than a code question.
It sounds like what you are looking for is a multinomial distribution. A very naive way of generating a distribution like that would be to think of it like throwing dice. Imagine that you have 200 dice with 9 sides each. Roll all of them. Count all the ones that ended up with the 1 side up, that would be your first number. Then count the ones that ended up with the 2 side up, that would be your second number. Continue until all dice are counted. There are 200 dice, so the sum of the counts will be 200. Each count would have the same probability distribution.
The above pseudo-algorithm would not be so efficient, basically looping over each die. Maybe efficiency is not so important in your case, (and 200 is a small number, so it does not matter) so feel free to write this algorithm.
If efficiency matters, try to find an existing implementation in a library. Maybe the MathNet library would work for you? See the Sample method if you are interested. At the very least, now that you know the term "multinomial distribution" it should be a bit easier to google for inspiration.
Imagine you have a bag of 200 coins. You need to divvy those coins into 9 random piles. A pile can have all the coins in the bag, some of the coins in the bag, or no coins.
Each time you allocate coins for a pile, the number of coins in the bag gets smaller (unless you grabbed 0 coins in which case it stays the same). This new count is referenced for the next pile allocation.
var rand = new Random();
var amount = 200;
var targetOutputValueCount = 9;
var outputValues = new List<int>();
for (int i = 1; i < targetOutputValueCount; i++) // 1 less than all groups
{
var groupAmount = rand.Next(0, amount);
amount -= groupAmount;
outputValues.Add(groupAmount);
}
// for the last group, it's whatever is left over
outputValues.Add(amount);
foreach (var outputValue in outputValues)
{
Console.WriteLine(outputValue);
}
An example output would be
148
28
0
2
12
2
1
6
1
The advantage of this approach is that you are always guaranteed to have positive output numbers.
Just generate eight numbers and compute the ninth as the missing difference:
int theSum = 200;
var randomNumbers = new int[9];
for(int i = 0; i < 8; i)
{
randomNumbers[i] = random.Next(0, theSum);
}
randomNumbers[8] = theSum - randomNumbers.Sum();
The methods proposed so far are workable, but tend to produce results that are skewed. For example, forcing the last number to give the correct sum can give you a value that is a long way off the other values (and possibly negative, which might be a problem in some cases). Calculating random values in the range from zero up to the remaining sum will give you a series of numbers that rapidly approach zero.
Instead, to generate n random numbers from 0 to total, I would suggest picking n-1 random values in the range from 0 to total (inclusive). Consider each of these values as the location of a bookmark in a deck of total cards. If the deck is then separated into n piles at these bookmarks, then the number of cards in each pile will give you a uniformly distributed set of values that sum to total.
Here's some code to illustrate the idea (in C, sorry):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int cmp(const void *a, const void *b) {
return *((int*)a) - *((int*)b);
}
int main(int argc, char *argv[]) {
int nterms, total, x, i, checksum;
int *array;
srand(time(0));
if (argc != 3) return puts("Require 2 arguments: <nterms> and <total>");
nterms = atoi(argv[1]); /* N.B. Input value checks omitted. */
total = atoi(argv[2]); /* Avoid large or negative values! */
/* We want to generate nterms intervals across the range from 0 to */
/* total (inclusive), so we need an array of nterms+1 values to mark */
/* the start and end of each interval. */
array = malloc((nterms+1) * sizeof(int));
/* The first and last items in this list must be zero and total (to */
/* ensure that the list of numbers add up to the correct amount) */
array[0] = 0;
array[nterms] = total;
/* Fill the rest of the array with random values from 0 to total. */
for (i=1; i<nterms; i++) {
array[i] = rand() % (total+1);
}
/* Sort these values in ascending order. */
qsort(array, nterms+1, sizeof(int), cmp);
/* Our list of random numbers can now be calculated from the */
/* difference between each pair of values in this list. */
printf("Numbers:");
for (i=checksum=0; i<nterms; i++) {
x = array[i+1] - array[i];
checksum += x;
printf(" %d", x);
}
printf("\nTotal: %d\n", checksum);
return 0;
}
You could also repeatedly generate 9 random numbers until they sum up to the desired sum. The optimal range for the random numbers is twice the target sum (200) divided by the number of random numbers (9) because then their average will be close to 200/9.
var random = new Random();
var randomNumbers = new int[9];
int input = 200;
int optimalRange = 2 * input / randomNumbers.Length;
int iterations = 0;
do {
for (int i = 0; i < randomNumbers.Length; i++) {
randomNumbers[i] = random.Next(optimalRange);
}
iterations++;
} while (randomNumbers.Sum() != input);
Console.WriteLine($"iterations = {iterations}");
Console.WriteLine($"numbers = {String.Join(", ", randomNumbers)}");
Example output:
iterations = 113
numbers = 2, 24, 39, 28, 6, 28, 34, 17, 22
In a test I repeated one million times I got these # of iterations:
average = 98.4
min = 1
max = 1366
And in 10170 cases I got it right at the first iteration.
Thanks for the hint #DrPhil. Here's a method using linq.
Random rnd = new Random();
int[] dice = new int[200];
var sidesUp = dice.Select(x => rnd.Next(1, 10));
List<int> randomNumbers = sidesUp.GroupBy(p => p).Select(x => x.Count()).ToList();
My approach ain't too different from others, but here it is:
Started by declaring an integer with the total value;
Subtracted the user input;
Used a for loop to iterate 8 times;
Each time get the division from remaining total and remaining iterations;
Option 1:
Used previous division as the maximum random value if remaining total is less than the max value;
Option 2:
Used previous division as the maximum random value;
The 9th number is the remaining total.
//run: RandomStats(0,101,200) for your particular example.
public static void RandomStats(int min, int max, int total)
{
Random randomClass = new Random();
int[] randomStats = new int[9];
int value = 0;
int totalValue = total;
bool parsed = false;
while (!parsed)
{
Console.WriteLine("Please enter a number:");
if (int.TryParse(Console.ReadLine(), out value))
{
parsed = true;
totalValue -= value;
for (int i = 0; i < randomStats.Length-1; i++)
{
//option 1
int remainMax = (int) Math.Floor((float) totalValue / (randomStats.Length - 1 - i));
int randomValue = randomClass.Next(min, totalValue < max ? remainMax : max);
//option 2
//max = (int) Math.Floor((float) totalValue / (randomStats.Length - 1 - i));
//int randomValue = randomClass.Next(min, max);
totalValue -= randomValue;
randomStats[i] = randomValue;
}
randomStats[8] = totalValue;
}
else
{
Console.WriteLine("Not a valid input");
}
}
Console.WriteLine($"min value: {min}\tmax value: {max}\ttotal value: {total}");
int testValue = value;
Console.WriteLine("Input value - " + value);
for (int i = 0; i < randomStats.Length; i++)
{
testValue += randomStats[i];
int randomIndex = i + 1;
Console.WriteLine(randomIndex + " Random value - " + randomStats[i]);
}
Console.WriteLine("test value - " + testValue);
Console.ReadKey();
}
option 1 output:
min value: 0 max value: 101 total value: 200
Input value - 10
1 Random value - 13
2 Random value - 2
3 Random value - 95
4 Random value - 10
5 Random value - 0
6 Random value - 15
7 Random value - 10
8 Random value - 10
9 Random value - 35
test value - 200
option 2 output:
min value: 0 max value: 67* total value: 200
Input value - 10
1 Random value - 1
2 Random value - 16
3 Random value - 5
4 Random value - 29
5 Random value - 17
6 Random value - 7
7 Random value - 48
8 Random value - 19
9 Random value - 48
test value - 200
*this was still 101 but became irrelevant since I divided remaining totals by the iterations

Using specific array count

My array max size is 20. If I were to enter data that would be less than 20,how do I get it where my program only counts the used arrays?
for (int i = 0; i < Score.Length; i++)
{
sum = sum + Score[i];
}
average = sum / Score.Length;
If I use this for loop above, it always divides by 20 for the average. I need it to only count the ones I entered, not 20. I would prefer solutions using arrays
If you insist in using arrays, then you must keep track of how many items you added to the array, like:
int[] Score = new int[20];
Random rdn = new Random();
int size=0;
for(int i=0;i<rdn.Next(0,20);i++)
{
Score[i] = rdn.Next();
size++;
}
int sum = 0;
for (int i = 0; i < size; i++)
{
sum = sum + Score[i];
}
double average = sum / size;
A better option is to use the List class that keep track for you of the number of items you add
List<int> Score = new List<int>();
Random rdn = new Random();
for(int i=0;i<rdn.Next(0,20);i++)
{
Score.Add(rdn.Next());
}
int sum = 0;
for (int i = 0; i < Score.Count; i++)
{
sum = sum + Score[i];
}
double average = sum / Score.Count;
And of course, as you didn't say the type of your data you could use other data types, like double, float, long, decimal for both solutions.
That is probably an overkill, but another approach would be to use a SparseVector class of the Math.Numerics package:
Sparse Vector uses two arrays which are usually much shorter than the vector. One array stores all values that are not zero, the other stores their indices.
PM > Install-Package MathNet.Numerics
var vector = SparseVector.Build.SparseOfArray(Score);
var sum = vector.Sum();
Sum() will only go through non-empty elements.
You need to keep track of the record that are != 0, so
int count = 0;
for(int i = 0; i < array.Length; i++)
{
if ( array[i] != 0 )
{
count++;
sum += array[i];
}
}
average = sum / count;
And beware of division by 0 ;)

generate random integers with a specific sum

I have 5 fields, I want them all to have a generated number between 0 and 100. But, the sum of the 5 fields should be 100.
When I want to give a random number for one field I would do the following:
Random rnd = new Random();
int x= rnd.Next(1, 10);
But how should I do that for multiple fields that needs to have a sum of 100 together?
You can use the following approach:
generate 4 random integers in [0, 100]
sort them, let's denote the sorted values as 0 ≤ x1 ≤ x2 ≤ x3 ≤ x4 ≤ 100
use the following 5 values as the random numbers with sum 100:
N1 = x1
N2 = x2 - x1
N3 = x3 - x2
N4 = x4 - x3
N5 = 100 - x4
It basically corresponds to randomly choosing 4 sectioning points on the [0, 100] interval, and using the lengths of the 5 resulting intervals as the random numbers:
const int k = 5;
const int sum = 100;
Random rnd = new Random();
int[] x = new int[k + 1];
// the endpoints of the interval
x[0] = 0;
x[k] = sum;
// generate the k - 1 random sectioning points
for (int i = 1; i < k; i++) {
x[i] = rnd.Next(0, sum + 1);
}
// sort the sectioning points
Array.Sort(x);
// obtain the k numbers with sum s
int[] N = new int[k];
for (int i = 0; i < k; i++) {
N[i] = x[i + 1] - x[i];
}
In order to make your distribution uniform, you could try the following aproach:
Generate some random numbers.
Normalize them.
Correct the last field to get exactly the expected sum, if needed.
The code:
const int ExpectedSum = 100;
Random rnd = new Random();
int[] fields = new int[5];
// Generate 4 random values and get their sum
int sum = 0;
for (int i = 0; i < fields.Length - 1; i++)
{
fields[i] = rnd.Next(ExpectedSum);
sum += fields[i];
}
// Adjust the sum as if there were 5 random values
int actualSum = sum * fields.Length / (fields.Length - 1);
// Normalize 4 random values and get their sum
sum = 0;
for (int i = 0; i < fields.Length - 1; i++)
{
fields[i] = fields[i] * ExpectedSum / actualSum;
sum += fields[i];
}
// Set the last value
fields[fields.Length - 1] = ExpectedSum - sum;
Live example: https://dotnetfiddle.net/5yXwOP
To achieve a truly random distribution, with every element having the chance to be 100 with a total sum of 100, you can use the following solution:
public static int[] GetRandomDistribution(int sum, int amountOfNumbers)
{
int[] numbers = new int[amountOfNumbers];
var random = new Random();
for (int i = 0; i < sum; i++)
{
numbers[random.Next(0, amountOfNumbers)]++;
}
return numbers;
}
static void Main(string[] args)
{
var result = GetRandomDistribution(100, 5);
}
It increases a random number by one until the sum is reached. This should fulfill all your criterias.
After thinking about it, I prefer the following solution, because it's less likely to generate an equal distribution:
public static int[] GetRandomDistribution2(int sum, int amountOfNumbers)
{
int[] numbers = new int[amountOfNumbers];
var random = new Random();
for (int i = 0; i < amountOfNumbers; i++)
{
numbers[i] = random.Next(sum);
}
var compeleteSum = numbers.Sum();
// Scale the numbers down to 0 -> sum
for (int i = 0; i < amountOfNumbers; i++)
{
numbers[i] = (int)(((double)numbers[i] / compeleteSum) * sum);
}
// Due to rounding the number will most likely be below sum
var resultSum = numbers.Sum();
// Add +1 until we reach "sum"
for (int i = 0; i < sum - resultSum; i++)
{
numbers[random.Next(0, amountOfNumbers)]++;
}
return numbers;
}
For Example.
int sum=100;
int i = 5;
Random rnd = new Random();
while (true)
{
int cur;
--i;
if (i == 0) {
Console.WriteLine(sum + " ");
break;
} else
cur=rnd.Next(1, sum);
sum -= cur;
Console.WriteLine(cur + " ");
}
Live Example: https://dotnetfiddle.net/ltIK40
or
Random rnd = new Random();
int x= rnd.Next(1, 10);
int y= rnd.Next(x,x+10);
int y2=rnd.Next(y,y+10);
int y3=rnd.Next(y2,y2+10);
int y4=100-(x+y+y2+y3);
My approach is this:
var rnd = new Random();
var numbers = Enumerable.Range(0, 5).Select(x => rnd.Next(0, 101)).ToArray().OrderBy(x => x).ToArray();
numbers = numbers.Zip(numbers.Skip(1), (n0, n1) => n1 - n0).ToArray();
numbers = numbers.Concat(new[] { 100 - numbers.Sum() }).ToArray();
This is as uniform as I think is possible.
Create your first random number. After that you take the difference between the value of num1 and 100 as the max def of rnd. But to guarantee that their sum is 100, you have to check at the last num if the sum of all nums is 100. If not the value of your last num is the difference that their sum and 100.
And to simply your code and get a clean strcuture, put that code in a loop and instead of single numbers work with an int[5] array.
private int[] CreateRandomNumbersWithSum()
{
int[] nums = new int[5];
int difference = 100;
Random rnd = new Random();
for (int i = 0; i < nums.Length; i++)
{
nums[i] = rnd.Next(0, difference);
difference -= nums[i];
}
int sum = 0;
foreach (var num in nums)
sum += num;
if (sum != 100)
{
nums[4] = 100 - sum;
}
return nums;
}
I think this is a very simple solution:
public void GenerateRandNr(int total)
{
var rnd = new Random();
var nr1 = rnd.Next(0, total);
var nr2 = rnd.Next(0, total - nr1);
var nr3 = rnd.Next(0, total - nr1 - nr2);
var nr4 = rnd.Next(0, total - nr1 - nr2 - nr3);
var nr5 = total - nr1 - nr2 - nr3 - nr4;
}
EDIT:
Just tested it, works fine for me:
The solution is that it's not the numbers that need to be random so much as the distribution needs to be random. The randomness of the numbers will be a side effect of their random distribution.
So you would start with five random numbers in a given range. The exact range doesn't matter as long as the range is the same for all five, although a broader range allows for more variation. I'd use Random.NextDouble() which returns random numbers between 0 and 1.
Each of those individual numbers divided by the sum of those numbers represents a distribution.
For example, say your random numbers are .4, .7, .2, .5, .2. (Using fewer digits for simplicity.)
The total of those numbers is 2. So now the distributions are each of those numbers divided by the total.
.4 / 2 = .20
.7 / 2 = .35
.2 / 2 = .10
.5 / 2 = .25
.2 / 2 = .10
You'll notice that those distributions will equal 100% or really close to it if there are a lot more decimal places.
The output is going to be each of those distributions times the target number, in this case, 100. In other words, each of those numbers represents a piece of 100.
So multiplying each of those distributions times the target, we get 20, 35, 10, 25, and 100, which add up to 100.
The trouble is that because of rounding your numbers won't always perfectly add up to 100. To fix that you might add one to the smallest number if the sum is less than 100, or subtract one from the largest number of the the sum is greater than 100. Or you could choose to add or subtract on one of the numbers at random.
Here's a class to create the distributions. (I'm just playing around so I haven't exactly optimized this to death.)
public class RandomlyDistributesNumbersTotallingTarget
{
public IEnumerable<int> GetTheNumbers(int howManyNumbers, int targetTotal)
{
var random = new Random();
var distributions = new List<double>();
for (var addDistributions = 0; addDistributions < howManyNumbers; addDistributions++)
{
distributions.Add(random.NextDouble());
}
var sumOfDistributions = distributions.Sum();
var output = distributions.Select(
distribution =>
(int)Math.Round(distribution / sumOfDistributions * targetTotal, 0)).ToList();
RoundUpOutput(output, targetTotal);
return output;
}
private void RoundUpOutput(List<int> output, int targetTotal)
{
var difference = targetTotal - output.Sum();
if (difference !=0)
{
var indexToAdjust =
difference > 0 ? output.IndexOf(output.Min()) : output.IndexOf(output.Max());
output[indexToAdjust]+= difference;
}
}
}
And here's a not-perfectly-scientific unit test that tests it many times over and ensures that the results always total 100.
[TestMethod]
public void OutputTotalsTarget()
{
var subject = new RandomlyDistributesNumbersTotallingTarget();
for (var x = 0; x < 10000; x++)
{
var output = subject.GetTheNumbers(5, 100);
Assert.AreEqual(100, output.Sum());
}
}
Some sample outputs:
5, 30, 27, 7, 31
15, 7, 26, 27, 25
10, 11, 23, 2, 54
The numbers are always going to average to 20, so while 96, 1, 1, 1 is a hypothetical possibility they're going to tend to hover closer to 20.
Okay. Having been burned by my previous attempt at this seemingly trivial problem, I decided to have another go. Why not normalise all the numbers after generation? This guarantees randomness, and avoids O(n log n) performance from a sort. It also has the advantage that even with my basic maths, I can work out that the numbers are uniformly distributed.
public static int[] UniformNormalization(this Random r, int valueCount, int valueSum)
{
var ret = new int[valueCount];
long sum = 0;
for (int i = 0; i < valueCount; i++)
{
var next = r.Next(0, valueSum);
ret[i] = next;
sum += next;
}
var actualSum = 0;
for (int i = 0; i < valueCount; i++)
{
actualSum += ret[i] = (int)((ret[i] * valueSum) / sum);
}
//Fix integer rounding errors.
if (valueSum > actualSum)
{
for (int i = 0; i < valueSum - actualSum; i++)
{
ret[r.Next(0, valueCount)]++;
}
}
return ret;
}
This should also be one of the fastest solutions.

c# - How to generate random ITIN

How to generate an 9 digit ITIN number with 70-88 in the fourth and fifth digit?
The IRS site says that
An Individual Taxpayer Identification Number (ITIN) begins with the number 9 and has a range of **70-88 in the fourth and fifth digit. The range was extended to include 900-70-0000 through 999-88-9999, 900-90-0000 through 999-92-9999 and 900-94-0000 through 999-99-9999.
My test is to validate that an error message is seen when user tries to input a valid ITIN
My code is checking for fourth and fifth digit after getting a random number.
A better way would be to get a random number with 9xx-70-0000 to 9xx-88-9999
int RangeOneBoundaryStart = 70;
int RangeOneBoundaryEnd = 88;
int count = 100;
string InvalidMsg = "Invalid Entry. Individual Tax Identification Numbers are not accepted.";
Random rand = new Random();
for (int i = 1; i <=count; i++ )
{
int Rndm1 = rand.Next(900700000, 999889999);
string num = Rndm1.ToString();
string chcknum = num.Substring(3, 2);
int chcknumint = Int32.Parse(chcknum);
if ( chcknumint >= RangeOneBoundaryStart && Rndm1 < RangeOneBoundaryEnd)
{
_applyPage.ClearField(VerifyElement);
_applyPage.EnterTextWithValue(VerifyElement, num);
_applyPage.Click(ClickAnotherElement);
_TestMethods.ValidateError(ElementToVld, InvalidMsg);
}
}
You could generate 3 different random numbers.
var rnd = new Random();
var rnd3 = rnd.Next(900, 1000); // 900 <= x < 1000
var rnd2 = rnd.Next(70, 89); // 70 <= x < 89
var rnd4 = rnd.Next(0, 10000); // 0 <= x < 10000
and then something like to generate the itin.
var itin = rnd3 + "-" + rnd2 + "-" + rnd4.ToString("0000");
https://dotnetfiddle.net/CpoWAq

Arrays and random numbers: count the times an integer is randomly generated [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Count Frequency in a Randomly Generated List of Numbers
I am currently working with arrays and random numbers. I have a created a form that will let me generate random numbers from 1 - 20 with a textbox1 to choose the quantity of numbers displayed. I am displaying the results inside a multiline textbox2. I have been able to calculate the sum and average of the set of numbers generated.
My second step:
Is there away to tally or mark the times a number is generated and display it in the multiline textbox(last picture)? Would I need to create an array and make it full of zero?
private void button1_Click(object sender, EventArgs e)
{
int n = Convert.ToInt32(textBox1.Text);
int[] y = new int[n];
double sum = 0;
for (int i = 0; i < n; i++)
{
int x = 1 + r.Next(20);
y[i] = x;
sum += x;
if (n < 101)
textBox2.AppendText(x + " ");
}
double avg = sum / n;
textBox2.AppendText(Environment.NewLine + sum + " " + avg + Environment.NewLine);
double vsum = 0;
for (int i = 0; i < n; i++)
vsum += (y[i] - avg) * (y[i] - avg);
}
Form.cs
Count the times an integer is randomly selected
"Would I need to create an array and make it full of zero?"
Yes, that would be a good start.
Have an array of counters (all initially zero) and count up the number of occurrences for each number as it appears.
Here's the code that can do what you want:
var r = new Random();
var n = int.Parse(this.textBox1.Text);
var y =
Enumerable
.Range(0, n)
.Select(x => r.Next(20) + 1)
.ToArray();
var sum = y.Sum();
var avg = (double)sum / (double)n;
var frequency = y.ToLookup(x => x);
textBox2.Text = String.Join(Environment.NewLine, new[]
{
"Results",
String.Format("{0} {1}", sum, avg),
}.Concat(Enumerable
.Range(1, 20)
.Select(x => String.Format("{0} ({1}x)", x, frequency[x].Count()))));
Running this with a value of 25 I got this result:
Results
278 11.12
1 (0x)
2 (2x)
3 (1x)
4 (1x)
5 (1x)
6 (2x)
7 (0x)
8 (1x)
9 (2x)
10 (4x)
11 (1x)
12 (0x)
13 (0x)
14 (0x)
15 (2x)
16 (1x)
17 (2x)
18 (2x)
19 (3x)
20 (0x)
Is that what you're after?
You can add a Dictionary<int, int> counter that counts. Insert those lines after int x = ...
if (counter.ContainsKey(x))
counter[x]++;
else
counter.Add(x, 1);
After that the dictionary holds one key value pair for each distinct random number you have created and the number of time it has been created. You could also use the dictionary to replace the y array altogether.
You could also do a
Dictionary<int,int>
store the number in question as the key (the first int)
store the number of times generated as the value (the second int).
Dictionary<int,int> numbers = new Dictionary<int,int>();
//initialize dictionary
for (int i = 1; i < 21; i++)
{
numbers.Add(i,0);
}
//this only covers generating number and adding to dictionary
Random random = new Random();
int nextNum = random.NextInt(1,20);
numbers[nextNum]++;
References:
http://www.dotnetperls.com/keyvaluepair
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx

Categories

Resources