如何仅使用一次随机值集中的值
How to use a value from a random value set only once
我正在尝试随机选择 15 个数组值。
我面临的问题是我希望在程序期间只生成一次值。
生成所有 15 个数字后,程序结束。
所以我的问题是,你如何确保一个值在程序中只生成一次。
int[] ImageValues = new int[15];
ImageValues[0] = 1;
ImageValues[1] = 2;
ImageValues[2] = 3;
ImageValues[3] = 4;
ImageValues[4] = 5;
ImageValues[5] = 6;
ImageValues[6] = 7;
ImageValues[7] = 8;
ImageValues[8] = 9;
ImageValues[9] = 10;
ImageValues[10] = 11;
ImageValues[11] = 12;
ImageValues[12] = 13;
ImageValues[13] = 14;
ImageValues[14] = 15;
Random randomize = new Random();
int initialValue = randomize.Next(0, 15);
int finalValue = ImageValues[initialValue];
最简单的解决方案是首先创建一个值列表...1-15,然后随机生成一个介于 0 和 14 之间的数字。
然后您从该位置获取值并将其从列表中删除。然后生成一个介于 0 和 13 之间的新随机数。依此类推,直到删除所有数字。
一个简单有效的解决方案是:
假设您有 N 个元素可供选择。
- 您从 0 到 N-1 中随机选择一个索引并删除选择的值
来自数组。
- 将数组的最后一个元素复制到
您删除的索引。
- 重复步骤 1-2 将数组视为短一个元素,因此第二次选择 0 和 N-2 之间的索引,然后是 0 和 N-3 等。
这保证您可以在恰好 K 次迭代中选择任何 K 个元素(因此该算法是确定性的)并且它保证了均匀分布。另一个好处是它不需要任何额外的内存分配。
首先,您还可以在声明数组时初始化数组,class 也应该有一个 Random
对象,这样您就可以重用它而不是每次都创建一个新对象。所以,也许在 ctor 中:
rand = new Random();
int[] ImageValues = new int[15]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
您可以使用单线 randomize/shuffle 它:
ImageValues = ImageValues.OrderBy(i => rand.Next()).ToArray();
这在很多情况下都可以正常工作。标准的 Fisher-Yates 洗牌被接受为快速且产生无偏顺序(如果使用正确),因此在某些情况下它可能更好:
private void ArrayShuffle(int[] items)
{
// uses the Random var declared earlier
int tmp = 0;
int j = 0;
// hi to low, so the rand result is meaningful
for (int i = items.Count() - 1; i >= 0; i += -1)
{
j = rand.Next(0, i + 1); // NB max param is EXCLUSIVE
tmp = items[j];
// swap j and Card i
items[j] = items[i];
items[i] = tmp;
}
}
无论哪种方式,一旦数组被打乱,您可以通过在构造函数中传递数组来使用它来创建 Stack
或 Queue
:
int[] ImageValues = new int[15];
// ...
ArrayShuffle(ImageValues);
Stack<int> mystack = new Stack<int>(ImageValues);
您可以只使用数组和一个指向要使用的索引的变量。使用集合类型消除了对该索引 var 的需求,并且当它 is/is 不递增时出现错误的可能性。对于纸牌游戏之类的东西,它模拟从牌组顶部开始处理下一张牌:
// ToDo:
// check myStack.Count() if times used is not controlled elsewhere
int nextVal = myStack.Pop();
我正在尝试随机选择 15 个数组值。 我面临的问题是我希望在程序期间只生成一次值。 生成所有 15 个数字后,程序结束。
所以我的问题是,你如何确保一个值在程序中只生成一次。
int[] ImageValues = new int[15];
ImageValues[0] = 1;
ImageValues[1] = 2;
ImageValues[2] = 3;
ImageValues[3] = 4;
ImageValues[4] = 5;
ImageValues[5] = 6;
ImageValues[6] = 7;
ImageValues[7] = 8;
ImageValues[8] = 9;
ImageValues[9] = 10;
ImageValues[10] = 11;
ImageValues[11] = 12;
ImageValues[12] = 13;
ImageValues[13] = 14;
ImageValues[14] = 15;
Random randomize = new Random();
int initialValue = randomize.Next(0, 15);
int finalValue = ImageValues[initialValue];
最简单的解决方案是首先创建一个值列表...1-15,然后随机生成一个介于 0 和 14 之间的数字。
然后您从该位置获取值并将其从列表中删除。然后生成一个介于 0 和 13 之间的新随机数。依此类推,直到删除所有数字。
一个简单有效的解决方案是:
假设您有 N 个元素可供选择。
- 您从 0 到 N-1 中随机选择一个索引并删除选择的值 来自数组。
- 将数组的最后一个元素复制到 您删除的索引。
- 重复步骤 1-2 将数组视为短一个元素,因此第二次选择 0 和 N-2 之间的索引,然后是 0 和 N-3 等。
这保证您可以在恰好 K 次迭代中选择任何 K 个元素(因此该算法是确定性的)并且它保证了均匀分布。另一个好处是它不需要任何额外的内存分配。
首先,您还可以在声明数组时初始化数组,class 也应该有一个 Random
对象,这样您就可以重用它而不是每次都创建一个新对象。所以,也许在 ctor 中:
rand = new Random();
int[] ImageValues = new int[15]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
您可以使用单线 randomize/shuffle 它:
ImageValues = ImageValues.OrderBy(i => rand.Next()).ToArray();
这在很多情况下都可以正常工作。标准的 Fisher-Yates 洗牌被接受为快速且产生无偏顺序(如果使用正确),因此在某些情况下它可能更好:
private void ArrayShuffle(int[] items)
{
// uses the Random var declared earlier
int tmp = 0;
int j = 0;
// hi to low, so the rand result is meaningful
for (int i = items.Count() - 1; i >= 0; i += -1)
{
j = rand.Next(0, i + 1); // NB max param is EXCLUSIVE
tmp = items[j];
// swap j and Card i
items[j] = items[i];
items[i] = tmp;
}
}
无论哪种方式,一旦数组被打乱,您可以通过在构造函数中传递数组来使用它来创建 Stack
或 Queue
:
int[] ImageValues = new int[15];
// ...
ArrayShuffle(ImageValues);
Stack<int> mystack = new Stack<int>(ImageValues);
您可以只使用数组和一个指向要使用的索引的变量。使用集合类型消除了对该索引 var 的需求,并且当它 is/is 不递增时出现错误的可能性。对于纸牌游戏之类的东西,它模拟从牌组顶部开始处理下一张牌:
// ToDo:
// check myStack.Count() if times used is not controlled elsewhere
int nextVal = myStack.Pop();