我需要创建一个包含十亿个整数的列表,它们必须都是唯一的。我还需要非常快速地完成这项工作。
创建一个列表并逐个添加随机数并检查每个是否重复是非常慢的。
如果我只使用随机数填充列表而不检查它们是否重复,然后使用distinct()。toList(),这似乎相当快。我重复这个,直到没有重复。但是,创建新列表所使用的额外内存不是最佳的。有没有办法获得distinct()的性能,但它只是修改源列表而不是创建一个新列表?
答案 0 :(得分:13)
整数是否需要在一定范围内?如果是这样,您可以创建一个数组或列表,其中包含该范围内的所有数字(例如1到1000000000)并随机播放该列表。
答案 1 :(得分:4)
我发现这是最快的,同时保持随机性:
Random rand = new Random();
var ints = Enumerable.Range(0, numOfInts)
.Select(i => new Tuple<int, int>(rand.Next(numOfInts), i))
.OrderBy(i => i.Item1)
.Select(i => i.Item2);
...基本上为每个int分配一个随机id,然后按该id排序并选择生成的int列表。
答案 2 :(得分:2)
您可以在单独的HashSet<int>
:
var set = new HashSet<int>();
var nums = new List<int>();
while(nums.Count < 1000000000) {
int num;
do {
num = rand.NextInt();
} while (!set.Contains(num));
set.Add(num);
list.Add(num);
}
您需要单独的List<int>
来存储数字,因为哈希集不会保留您的随机排序。
答案 3 :(得分:2)
从字面上理解这个问题(一个包含10亿个整数的列表,它们必须都是唯一的):
Enumerable<int>.Range(0, 1000000000)
但是按照CodeCaster的回答,您可以创建列表并同时对其进行随机播放:
var count = 1000000000;
var list = new List<int>(count);
var random = new Random();
list.Add(0);
for (var i = 1; i < count; i++)
{
var swap = random.Next(i - 1);
list.Add(list[swap]);
list[swap] = i;
}
答案 4 :(得分:1)
如果您绘制的可能整数的数量(比如因子2)明显大于您想要的整数数量,则只需使用HashSet<T>
来检查重复项。
List<int> GetUniqueRandoms(Random random, int count)
{
List<int> result = new List<int>(count);
HashSet<int> set = new HashSet<int>(count);
for(int i = 0; i < count; i++)
{
int num;
do
{
num = random.NextInt();
while(!set.Add(num));
result.Add(num);
}
return result;
}
这会为集合分配正确的容量,以避免在增长期间重新分配。由于您的藏品很大,这应该是一个很大的改进。
您也可以一次使用Distinct
:
IEnumerable<int> RandomSequence(Random random)
{
while(true)
{
yield return random.NextInt();
}
}
RandomSequence(rand).Distinct().Take(1000000000).ToList();
但是对于这两种解决方案,您需要足够的内存来HashSet<int>
和List<int>
。
如果您绘制的可能整数的数量与您想要的整数数量一样大,您可以创建一个包含所有整数的数组,将它们随机播放,最后切断那些您不感兴趣的数组。
答案 5 :(得分:0)
如果您以排序但仍然随机的方式创建列表(例如将随机数添加到列表的最后一个元素作为下一个元素),然后使用Fisher-Yates-Durstenfeld对列表进行洗牌,该怎么办?这将在整体线性时间内执行,这与列表生成一样好。但是,它可能会产生一些影响分布的显着偏差。