使用扩展方法的集合随机化

时间:2009-12-14 15:34:42

标签: c# extension-methods

  

可能重复:
  C#: Is using Random and OrderBy a good shuffle algorithm?

我想创建一个扩展方法,该方法应该对集合中的项进行随机播放。

我可以改进以下内容吗?

public static IList<T> RandomList<T>(this IList<T> source)
{
   if (source.Count <= 0) throw new ArgumentException("No Item to Randomize");  

            for (int i =source.Count-1 ; i>0; i--)
            {
                int RandomIndex = Rnd.Next(i + 1);
                T temp = source[i];
                source[i] = source[RandomIndex];
                source[RandomIndex] = temp;
            }

            return source;
 }

5 个答案:

答案 0 :(得分:5)

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
   foreach(var item in source.OrderBy(i => Guid.NewGuid()))
   {
      yield return item;
   }
}

答案 1 :(得分:1)

只要你知道Random is not very random.

,我认为这就足够了
  

随机类适用于简单游戏和其他非科学领域。不要将它用于加密。

答案 2 :(得分:1)

通常,您应该避免更改列表,而是返回一个新列表。更好的方法是返回IEnumerable以与其他Extension方法和LINQ保持一致。

试试这个。

public static class RandomizeExtensionMethods
{
    private static readonly Random _random = new Random();

    public static IEnumerable<T> Randomize<T>(this IList<T> enumerable)
    {
        if (enumerable == null || enumerable.Count == 0)
        {
            return new List<T>(0);
        }

        return RandomizeImpl(enumerable);           
    }

    public static IEnumerable<T> RandomizeImpl<T>(this IList<T> enumerable)
    {
        var indices = new int[enumerable.Count];
        for(int i=0; i<indices.Length; i++)
        {
            indices[i] = i;
        }

        lock (_random)
        {
            for (int i = 0; i < indices.Length - 1; i++)
            {
                int j = _random.Next(i, indices.Length);
                int swap = indices[j];
                indices[j] = indices[i];
                indices[i] = swap;
            }
        }

        for(int i=0; i<indices.Length; i++)
        {
            yield return enumerable[indices[i]];
        }
    }
}

答案 3 :(得分:1)

我对这种方法有一些问题:

  • 应检查空参数。
  • 不应检查0长度列表。
  • 避免副作用。为混洗元素创建一个新列表,而不是修改现有元素。
  • 不要隐藏依赖项。将随机数生成器作为参数传递。
  • 使用比“RandomList”更具描述性的名称。
  • 输入类型可以推广到IEnumerable。
  • 该方法可以更改为枚举器[概括输出类型]。

本质:

public static IList<T> Shuffled<T>(this IEnumerable<T> source, Random generator)
{
    if (source == null) throw new ArgumentNullException("source");
    if (generator == null) throw new ArgumentNullException("generator");

    //copy
    var result = source.ToList();
    //shuffle the copy
    for (int i = result.Count - 1; i > 0; i--)
    {
        int RandomIndex = generator.Next(i + 1);
        T temp = result[i];
        result[i] = result[RandomIndex];
        result[RandomIndex] = temp;
    }

    return result;
}

我没有概括输出类型。如果你愿意,你可以这样做。

答案 4 :(得分:0)

让它返回本身有点多余。如果您要返回列表的深层副本,请确保;在这种情况下,它应该被称为“GetShuffledCopy()”或类似的东西。如果你在列表本身上行动,它应该是一个无效的回报,并被称为“Shuffle()”

-Oisin