这个问题已经在这里有了答案 :
最佳LINQ查询以获取随机子集合-随机播放 (7个答案)
4年前关闭。
我需要一个扩展方法,它将洗牌IEnumerable<T>。也可能需要int指定来返回的大小IEnumerable。更好地保持网络的不变性IEnumerable。我当前的解决方案IList-
IEnumerable<T>
int
IEnumerable
IList
public static IList<T> Shuffle<T>(this IList<T> list, int size) { Random rnd = new Random(); var res = new T[size]; res[0] = list[0]; for (int i = 1; i < size; i++) { int j = rnd.Next(i); res[i] = res[j]; res[j] = list[i]; } return res; } public static IList<T> Shuffle<T>(this IList<T> list) { return list.Shuffle(list.Count); }
您可以使用Fisher-Yates- Durstenfeld混洗。不需要显式地将size参数传递给方法本身,Take如果不需要整个序列,则可以简单地进行调用:
Take
var shuffled = originalSequence.Shuffle().Take(5); // ... public static class EnumerableExtensions { public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) { return source.Shuffle(new Random()); } public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng) { if (source == null) throw new ArgumentNullException("source"); if (rng == null) throw new ArgumentNullException("rng"); return source.ShuffleIterator(rng); } private static IEnumerable<T> ShuffleIterator<T>( this IEnumerable<T> source, Random rng) { var buffer = source.ToList(); for (int i = 0; i < buffer.Count; i++) { int j = rng.Next(i, buffer.Count); yield return buffer[j]; buffer[j] = buffer[i]; } } }