How do I generate 30 random numbers between 1-9, that all add up to 200 (or some arbitrary N), in C#?
I\'m trying to generate a string of digits that can add togethe
Algorithm:
After all the discussions here, there's one other way to generate a list that doesn't introduce bias. Yes, it does differ from what the question is asking, but instead of randomly choosing digits, you can randomly increment digits until you reach the sum. Like the following (again untested):
public static List<int> RandomListByIncrementing(int digitMin, int digitMax,
int targetSum, int numDigits)
{
if(targetSum < digitMin * numDigits || targetSum > digitMax * numDigits)
throw new ArgumentException("Impossible!", "targetSum");
List<int> ret = new List<int>(Enumerable.Repeat(digitMin, numDigits));
List<int> indexList = new List<int>(Enumerable.Range(0, numDigits-1));
Random random = new Random();
int index;
for(int currentSum=numDigits * digitMin; currentSum<targetSum; currentSum++)
{
//choose a random digit in the list to increase by 1
index = random.Next(0,indexList.Length-1);
if(++ret[indexList[index]] == digitMax)
{
//if you've increased it up to the max, remove its reference
//because you can't increase it anymore
indexList.RemoveAt(index);
}
}
return ret;
}
The idea here is you keep a list of references to your number list. Choose a reference at random, and increment the corresponding number. If you can't increment it anymore, remove the reference so you don't choose it next time.
Now there's no shuffling business to be done at the end of the day, although arguably this will still produce one of the available sets of answers to the question and it's a question of which one "feels better" or is faster to run.
This is an old question but I discovered it looking for a solution to this problem for a practical use in a random data generation testing application.
Based on the ideas in this post I came up with two potential solutions.
The first method:
The second method is much simpler but results in a less random distribution:
Here is the code:
public static int[] getRandomsWithTotalA(int desiredTotal, int desiredNumbers, int upperBound)
{
Random r = new Random();
// Is this even a possible feat?
if (desiredNumbers * upperBound < desiredTotal) throw new ArgumentException("This is not possible!", "desiredTotal");
// Start by figuring out the closest number we can get to by repeating the initial number.
int lowestRepeating = desiredTotal / desiredNumbers;
// Determine the remainder
int lowestRepeatingRemainder = desiredTotal % desiredNumbers;
// Initialize and populate an array of numbers with the lowest repeater.
int[] results = Enumerable.Repeat(lowestRepeating, desiredNumbers).ToArray();
// We will perform (n*desiredTotal) shuffles.
int shuffles = (desiredTotal * desiredNumbers);
while (shuffles > 0)
{
int a = r.Next(desiredNumbers);
int b= r.Next(desiredNumbers);
if (a==b) continue; // do nothing if they're equal - try again.
// Test bounds.
if (results[a]+1>upperBound) continue;
if (results[b]-1<0) continue;
// Add one to the first item.
results[a]++;
// Do we still have a remainder left? If so, add one but don't subtract from
// somewhere else.
if (lowestRepeatingRemainder>0)
{
lowestRepeatingRemainder--;
continue;
}
// Otherwise subtract from another place.
results[b]--;
// decrement shuffles
shuffles--;
}
return results;
}
public static int[] getRandomsWithTotalB(int desiredTotal, int desiredNumbers, int upperBound)
{
Random r = new Random();
// Is this even a possible feat?
if (desiredNumbers * upperBound < desiredTotal) throw new ArgumentException("This is not possible!", "desiredTotal");
// Initialize and populate an array of numbers with the lowest repeater.
int[] results = new int[desiredNumbers];
while (desiredTotal > 0)
{
int a = r.Next(desiredNumbers);
// Test bounds.
if (results[a] + 1 > upperBound) continue;
// Add one to the first item.
results[a]++;
desiredTotal--;
}
return results;
}
A sample run:
static void Main(string[] args)
{
foreach (int i in getRandomsWithTotalA(200, 30, 9))
{
Console.Write("{0}, ", i);
}
Console.WriteLine("\n");
foreach (int i in getRandomsWithTotalB(200, 30, 9))
{
Console.Write("{0}, ", i);
}
}
3, 8, 7, 5, 9, 9, 8, 9, 9, 6, 8, 7, 4, 8, 7, 7, 8, 9, 2, 7, 9, 5, 8, 1, 4, 5, 4, 8, 9, 7,
6, 8, 5, 7, 6, 9, 9, 8, 5, 4, 4, 6, 7, 7, 8, 4, 9, 6, 6, 5, 8, 9, 9, 6, 6, 8, 7, 4, 7, 7,
These methods are understandably not as evenly distributed as one would like. It would make sense especially with the second method; if you have a random source that is truly evenly distributed, then your selection of the items to increment should have equal probability across all the possible values. The first one could potentially be a bit better also, but it still suffers from the fact that the random source is also ideally evenly distributed.
I feel like it might be possible to improve at least the first method by introducing some form of bias into the index selection, or possibly a randomization of how much we add and subtract (not always 1), or a randomization of whether we actually do the addition/subtraction or not. Just tweaking the number of iterations seems to change the distribution, but after a while it seems that we start favoring the outer boundaries. (Perhaps it's not possible to get a truly even distribution!)
In any case, there you go...A good place to start at least.
This program will attempt to give you the answer. But because you are dealing with random numbers, there is the possibility that this will never give you the answer.
public static IEnumerable<int> GetRandom()
{
var rand = new Random();
while (true)
{
yield return
rand.Next(1, 9);
}
}
public static List<int> GetThirtyThatAddToTwoHundred()
{
do
{
var current = GetRandom().Take(30);
if (200 == current.Sum())
{
return current.ToList();
}
} while (true);
}
This method will return 30 random numbers that add up to an arbitraryN. It is possible do, to have some 0 values. if that is not feasible, just initialize the array all to one's and if the sum is greater to the arbitraryN, set vals[nextIdx] to 1 instead of 0. Hope this helps.
private int[] getNumbers(int arbitraryN) {
int[] vals = new int[30];
int nextIdx = 0;
int nextNumber=0;
Random r = new Random();
if (arbitraryN > 270 || arbitraryN < 30)
throw new Exception("Not a Valid number");
while (vals.Sum() < arbitraryN)
{
nextNumber = r.Next(1, 9);
nextIdx = r.Next(29);
vals[nextIdx] = nextNumber;
if (vals.Sum() > arbitraryN)
{
vals[nextIdx] = 0;
vals[nextIdx] = 270 - vals.Sum();
break;
}
}
return vals;
}
public static List<int> getNumbers(int n)
{
Random random = new Random(DateTime.Now.Millisecond);
List<int> obtainedNumbers = new List<int>();
do
{
obtainedNumbers.Add(random.Next(1, 9));
}
while (n - obtainedNumbers.Sum() > 0);
return obtainedNumbers;
}
JaredPar code likes me but its slow, it's like to throw a coin and hope to get the n value.Nice pieces of codes