I needed to take an array of (C#) integers and randomly reassign values to make the values "feel" more randomized, without changing the length or sum of the array. But this array can get quite large, so I'm wondering if anyone has a better way to do this. Basically, the array initially contains values that are roughly the sum divided by the length, with one element having the remainder. What I am using now is:
static int[] AddEntropy(int[] ia)
{
int elements = ia.Length;
int sum = ia.Sum();
for (int runs = 0; runs < (elements * 2); runs++)
{
Random rnd = new Random(int.Parse(Guid.NewGuid().ToString().Substring(0, 8), System.Globalization.NumberStyles.HexNumber));
int rndi = rnd.Next(0, (sum / elements));
int rnde1 = rnd.Next(0, elements);
int rnde2 = rnd.Next(0, elements);
if (rndi < 1 ) rndi = 1;
if (ia[rnde1] > (rndi + 2))
{
ia[rnde1] = ia[rnde1] - rndi;
ia[rnde2] = ia[rnde2] + rndi;
}
}
return ia;
}
Any thoughts on making this perform better would be appreciated. It seems to perform "well", but if the array are larger than my sample of five elements (up to 1000 elements), and there are several arrays that may be modified in quick succession, a speedier option would be great.
If I understood everything correctly the task requires the sum of the elements to be preserved. Then there is no need in initial array elements values, the two thing that matter are the sum of the elements and the number of the elements.
public static int[] GetArray(int sum, int n)
{
if(sum < n)
throw new ArgumentException("sum is lower than n");
Random rnd = new Random();
// reserve 1 for each of the elements
sum -= n;
// generate random weights for every element in sum
int[] w = new int[n];
int sw = 0;
for (int i = 0; i < n; i++)
{
w[i] = rnd.Next(0, 100);
sw += w[i];
}
// generate element values based on their weights
int[] result = new int[n];
int tsum = 0;
int psum = 0;
for (int i = 0; i < n; i++)
{
tsum += w[i] * sum;
result[i] = tsum / sw - psum;
psum += result[i];
}
// restore reserved ones
for (int i = 0; i < n; i++)
result[i]++;
return result;
}