需要洗牌的IEnumerable的扩展方法 [英] An extension method on IEnumerable needed for shuffling

查看:127
本文介绍了需要洗牌的IEnumerable的扩展方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个扩展方法,这将洗牌的的IEnumerable< T> 。它也可以采取 INT 来指定返回的IEnumerable 的大小。更好地保持的IEnumerable 的不变性。我对目前的解决方案的IList -

 公共静态的IList< T>随机< T>(这个IList的< T>列表,INT大小)
{
    随机RND =新的随机();
    VAR解析度=新的T [大小]    RES [0] =列表[0];
    的for(int i = 1; I<大小;我++)
    {
        诠释J = rnd.Next(ⅰ);
        RES [I] = RES [J]。
        RES [J] =列表[我]
    }
    返回水库;
}公共静态的IList< T>随机< T>(这个IList的< T>清单)
{返回list.Shuffle(list.Count); }


解决方案

您可以使用的费雪耶茨-Durstenfeld洗牌。有没有必要为一个大小参数明确传递给方法本身,你可以简单地钉上的 如果你不需要整个序列:

  VAR洗牌= originalSequence.Shuffle()采取(5)。// ...公共静态类EnumerableExtensions
{
    公共静态的IEnumerable< T>随机< T>(这个IEnumerable的< T>源)
    {
        返回source.Shuffle(新随机());
    }    公共静态的IEnumerable< T>随机< T>(这个IEnumerable的< T>源,随机RNG)
    {
        如果(来源== NULL)抛出新的ArgumentNullException(源);
        如果(RNG == NULL)抛出新的ArgumentNullException(RNG);        返回source.ShuffleIterator(RNG);
    }    私有静态的IEnumerable< T> ShuffleIterator< T>(
        这IEnumerable的< T>源,随机RNG)
    {
        VAR缓冲= source.ToList();
        的for(int i = 0; I< buffer.Count;我++)
        {
            INT J = rng.Next(I,buffer.Count);
            产量返回缓冲区[J]。            缓冲[J] =缓冲[I]
        }
    }
}

I need an extension method which will shuffle an IEnumerable<T>. It can also take an int to specify the size of the returned IEnumerable. Better keeping Immutability of the IEnumerable. My current solution for 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); }

解决方案

You can use a Fisher-Yates-Durstenfeld shuffle. There's no need to explicitly pass a size argument to the method itself, you can simply tack on a call to Take if you don't need the entire sequence:

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];
        }
    }
}

这篇关于需要洗牌的IEnumerable的扩展方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆