【发布时间】:2011-03-27 21:18:51
【问题描述】:
我想限制 c# 中的随机类,比如从 2 个范围内生成随机变量而不重复? 示例:
Xpoints[i] = random.Next(0, 25);
Ypoints[i] = random.Next(0, 12);
其中 25 我们 12 是图像尺寸,所以我需要此图像中的所有像素但随机?如果我使用此代码有任何建议,我没有得到一些像素和一些重复的像素
【问题讨论】:
我想限制 c# 中的随机类,比如从 2 个范围内生成随机变量而不重复? 示例:
Xpoints[i] = random.Next(0, 25);
Ypoints[i] = random.Next(0, 12);
其中 25 我们 12 是图像尺寸,所以我需要此图像中的所有像素但随机?如果我使用此代码有任何建议,我没有得到一些像素和一些重复的像素
【问题讨论】:
更新无需任何特定散列即可简化 [1]
更新泛化为通用的SimpleShuffle扩展方法
public static IEnumerable<T> SimpleShuffle<T>(this IEnumerable<T> sequence)
{
var rand = new Random();
return sequence.Select(i => new {i, k=rand.Next()})
.OrderBy(p => p.k)
.Select(p => p.i);
}
我除了投反对票(大喊?对不起 :))Anx 的回答我认为最好也显示我的代码的样子:
using System;
using System.Linq;
using System.Collections.Generic;
namespace NS
{
static class Program
{
public static IEnumerable<T> SimpleShuffle<T>(this IEnumerable<T> sequence)
{
var rand = new Random();
return sequence.Select(i => new {i, k=rand.Next()}).OrderBy(p => p.k).Select(p => p.i);
}
public static void Main(string[] args)
{
var pts = from x in Enumerable.Range(0, 24)
from y in Enumerable.Range(0, 11)
select new { x, y };
foreach (var pt in pts.SimpleShuffle())
Console.WriteLine("{0},{1}", pt.x, pt.y);
}
}
}
我完全解决了我之前的问题,即如何通过意识到我们不需要散列来生成一个好的散列,除非:
一个。和 b。在这种情况下是错误的,并且 c。甚至会成为一个问题(取决于 OP 的要求)。所以现在,没有任何附加条件,不再担心性能(甚至是非理性的担心),
祝你好运!
[1] 顺便说一句,这使整个事情更加灵活,因为我不再需要用字节 [] 来表示坐标;您现在可以随机播放您想要的任何结构。
【讨论】:
看看Fisher-Yates算法:
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
它很容易实现,而且效果很好。
它会打乱一组数字,然后您可以按顺序访问它们,以确保没有重复。
【讨论】:
您可能希望对索引列表(例如,X 轴值为 0..24 的 25 个元素)而不是随机使用随机播放算法。
随机设计不保证没有重复值;重复的可能性很大。
另请参阅:Optimal LINQ query to get a random sub collection - Shuffle(查找 Fisher-Yates-Durstenfeld 解决方案)
【讨论】:
我也相信,Random 不应该是可预测的,我们甚至不应该预测该值不会重复。
但我认为有时可能需要随机获取非重复 int,因为我们需要维护状态,例如 Random 类的特定实例,返回所有值。
这是我刚才想到的算法的一个快速而肮脏的小实现,我不确定它是否与 Fisher-Yates 解决方案相同。我刚刚编写了这个类,以便您可以使用它来代替 System.Random 类。
所以它可以帮助您满足您的要求,根据您的需要使用下面的 NonRepeatingRandom 类...
class NonRepeatingRandom : Random
{
private HashSet<int> _usedValues = new HashSet<int>();
public NonRepeatingRandom()
{
}
public NonRepeatingRandom(int seed):base(seed)
{
}
public override int Next(int minValue, int maxValue)
{
int rndVal = base.Next(minValue, maxValue);
if (_usedValues.Contains(rndVal))
{
int oldRndVal = rndVal;
do
{
rndVal++;
} while (_usedValues.Contains(rndVal) && rndVal <= maxValue);
if (rndVal == maxValue + 1)
{
rndVal = oldRndVal;
do
{
rndVal--;
} while (_usedValues.Contains(rndVal) && rndVal >= minValue);
if (rndVal == minValue - 1)
{
throw new ApplicationException("Cannot get non repeating random for provided range.");
}
}
}
_usedValues.Add(rndVal);
return rndVal;
}
}
请不要只覆盖“Next”方法,而不是其他方法,如果您愿意,您也可以覆盖“Random”类的其他方法。
附言。就在单击“发布您的答案”之前,我看到了 sehe 的答案,我喜欢他的整体想法,但是要散列 2 个字节,创建一个 16 字节的散列?还是我错过了什么?在我的代码中,我使用的是 HashSet,它使用 int 的 GetHashCode 方法实现,它只是 int 本身的值,因此没有散列开销。但我可能会错过一些要点,因为现在是印度凌晨 3:59 :)
希望它可以帮助萨拉蒙蒂...
【讨论】:
(pt[1]*random1)^(pt[0]*random2) 这样的简单哈希,其中 random1 和 random2 足够大的静态随机整数。稍后我可能会编辑代码以包含真正的哈希(但有一些陷阱:需要考虑使用unchecked multiplcations 等。千万不要在午夜之后执行哈希实现 SERIOUS :)
随机数的全部意义在于你确实会得到重复。
但是,如果您想确保在选择下一个数字之前不要从数组中删除最后选择的值。所以如果你有一个数字列表:
index = random.Next(0, originallist.Length);
radomisedList.Add(originalList[index]);
originalList.RemoveAt(index);
列表将随机排列,但不包含重复。
【讨论】:
您应该通过一个二维矩阵创建图像,而不是通过两个一维数组创建图像。每次获得新的随机坐标时,检查该像素是否已设置。如果是,则对该像素重复该过程。
【讨论】: