这是我的Linq代码,用于生成随机数列表,其中包含10个数字,范围从0到20
Random rand = new Random();
var randomSeq = Enumerable.Repeat(0, 10).Select(i => rand.Next(0,20));
结果:
6
19
18
7
18
12
12
9
2
18
你可以看到我有三个18和两个12 ..
我曾尝试使用Distinct()函数,但它不会填满列表(例如只填充10个数字中的8个) 问题:如何生成唯一编号(即不可重复的数字) 非常感谢
答案 0 :(得分:8)
您希望生成数字0到19的随机排列,并选择其中10个数字。用于生成随机排列的标准算法是Fisher-Yates shuffle。生成随机排列后,您可以选择前10个数字。
如果碰撞发生但是它们通常无法具有良好的统计属性,具有不确定的运行时间或者甚至不能保证在最坏的情况下终止,那么就不难想出像ad-hoc算法那样重复选择新的数字。情况下。
请注意,如果数字的顺序不同,则此解决方案不是一个好选择。生成数百万以下的数字只能选择10,这不是最聪明的事情。
<强>更新强>
我刚刚意识到你可以在生成排列的前十个元素后停止算法 - 不需要构建整个排列。
答案 1 :(得分:5)
在函数式编程中,通常会创建无限序列。起初听起来有点奇怪,但在某些情况下它可能非常有用。假设你有这样的延伸:
public static class EnumerableExtentions
{
public static IEnumerable<T> Infinite<T>(Func<int, T> generator)
{
int count = 0;
checked {
while (true)
yield return generator(count++);
}
}
}
我可以用它来创建无限的序列,如:
var oddNumbers = EnumerableExtentions.Infinite(n => 2*n + 1)
这是所有奇数的无限序列。我可以只采取前10个,例如:
oddNumbers.Take(10);
会产生:
1 3 5 7 9 11 13 15 17 19
由于延迟执行,我们得不到StackOverflowException(你必须小心)。
可以使用相同的原理创建无限随机序列,区分它然后取第10个:
var r = new Random();
var randomNumbers = EnumerableExtentions
.Infinite(i=> r.Next (0, 20))
.Distinct()
.Take(10);
如果需要,您可以在最后制作OrderBy(s =&gt; s)。
答案 2 :(得分:3)
在LINQ exchange,他们讨论了一种使用LINQ随机重新排序列表的方法,并给出一个代码示例,它将生成所需数字的随机排列。
他们说(解释,并适应这个问题):
使用LINQ OrderBy随机排序列表数组
// create and populate the original list with 20 elements
List<int> MyList = new List<int>(20);
for (int i = 0; i < 20; i++)
MyList.Add(i);
// use System.GUID to generate a new GUID for each item in the list
List<int> RandomList = MyList.OrderBy(x => System.Guid.NewGuid()).ToList();
LINQ OrderBy然后将按返回的GUID列表对数组进行排序。
现在你可以拿下列表的前10个元素,然后就可以得到解决方案了。
他们注意到使用System.Guid.NewGuid()会产生与Fisher-Yates shuffle算法相同的分布范围,这样您就不必自己实际实现算法。
答案 3 :(得分:2)
为什么不这样做:
Enumerable.Range(0, 20)
.OrderBy(x => Guid.NewGuid().GetHashCode())
.Distinct()
.Take(10)
.ToArray();
答案 4 :(得分:1)
只需创建顺序有效数字列表即可。然后从该列表中生成一个随机索引,并返回(并从列表中删除)索引处的数字。
static class Excensions
{
public static T PopAt<T>(this List<T> list, int index)
{
T ret = list[index];
list.RemoveAt(index);
return ret;
}
}
class Program
{
static void Main()
{
Random rng = new Random();
int length = 10; //sequence length
int limit = 20; //maximum value
var avail = Enumerable.Range(0, limit).ToList();
var seq = from i in Enumerable.Range(0, length)
select avail.PopAt(rng.Next(avail.Count));
}
}
答案 5 :(得分:1)
如何使用实用程序可枚举方法:
static IEnumerable<int> RandomNumbersBetween(int min, int max)
{
int availableNumbers = (max - min) + 1 ;
int yieldedNumbers = 0;
Random rand = new Random();
Dictionary<int, object> used = new Dictionary<int, object>();
while (true)
{
int n = rand.Next(min, max+1); //Random.Next max value is exclusive, so add one
if (!used.ContainsKey(n))
{
yield return n;
used.Add(n, null);
if (++yieldedNumbers == availableNumbers)
yield break;
}
}
}
因为它返回IEnumerable,你可以将它与LINQ和IEnumerable扩展方法一起使用:
RandomNumbersBetween(0, 20).Take(10)
或者只取奇数:
RandomNumbersBetween(1, 1000).Where(i => i%2 == 1).Take(100)
等等。
修改强>
请注意,如果您尝试在min
和max
之间生成一组完整的随机数,则此解决方案具有糟糕的性能特征。
然而,如果你想生成0到20之间的10个随机数,甚至更好,0到1000之间,它会有效地工作。
在最糟糕的情况下,它还可以占用(max - min)
空间。
答案 6 :(得分:0)
将生成的结果存储在一个数组中,因此任何时候生成新的数字检查是否已经生成过,如果是,则生成另一个,否则取数字并将其保存在数组中
答案 7 :(得分:0)
使用自定义RepeatUntil扩展并依赖闭包:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
public static class CoolExtensions
{
public static IEnumerable<TResult> RepeatUntil<TResult>( TResult element, Func<bool> condition )
{
while (!condition())
yield return element;
}
}
class Program
{
static void Main( string[] args )
{
Random rand = new Random();
HashSet<int> numbers = new HashSet<int>();
var randomSeq = CoolExtensions.RepeatUntil( 0, () => numbers.Count >= 10).Select( i => rand.Next( 0, 20 ) ).Select( x => numbers.Add(x));
// just used to evaluate the sequence
randomSeq.ToList();
foreach (int number in numbers)
Console.WriteLine( number );
Console.ReadLine();
}
}
}
答案 8 :(得分:0)
为什么不随机订购?像这样
var rnd = new Random();
var randomSeq = Enumerable.Range(1,20).OrderBy(r => rnd.NextDouble()).Take(10).ToList();
答案 9 :(得分:-4)
你能做这样的事吗?
Random rand = new Random();
var randomSeq = Enumerable.Range(0, 20).OrderBy(i => rand.Next(0,20)).Take(10);