试图获得随机排序顺序

时间:2017-01-17 12:05:07

标签: c# linq random

使用C#/ Asp.Net。

我正在努力实现以下目标:

我有一份报价清单 - 有时会有多个价格相同的产品。

此外,部分结果属于附属(赞助),因此我们也需要优先考虑。

以下是调用的方法:

    public IEnumerable<PriceQuote> BestQuote(int take = 0)
    {
        var q = Quotes.Where(x => x.TotalRepayable == MinPrice)
            .Shuffle()
            .OrderByDescending(x => x.ProductDetail.Product.IsSponsored);

        return take == 0 ? q : q.Take(take);
    }

代码选择具有最低可用价格的商品。然后我们的想法是将它们排序成一个完全随机的顺序,然后再按赞助标志降序排序(赞助= 1而不是0),然后需要很多结果。

我首先将它们随机播放以获得随机顺序 - 从随机列表中我想首先获得赞助项目 - 然后在必要时用非赞助项目填充空格。该理论认为,赞助和非赞助每次都是随机的。

Example in natural order:

product1 (not sponsored)
product2 (sponsored)
product3 (not sponsored)
product4 (sponsored)
product5 (not sponsored)
product6 (sponsored)

Shuffle randomly:

product3 (not sponsored)
product1 (not sponsored)
product2 (sponsored)
product6 (sponsored)
product5 (not sponsored)
product4 (sponsored)

Order by sponsored first keeping randomness:

product2 (sponsored) <-- pick these first
product6 (sponsored)
product4 (sponsored)
product3 (not sponsored)
product1 (not sponsored)
product5 (not sponsored)

这是我的Shuffle方法:

    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> @this)
    {
         if (@this.Count() <= 1) return @this;

        return @this.ShuffleIterator(new Random());
    }

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

我遇到的问题是,当我为不同的引号连续多次调用BestQuote方法时,我倾向于返回相同的结果。例如,我的列表包含6个产品,我每次拨打3个电话选择第一个结果,可能是所有3个电话的订单相同。情况并非总是如此 - 存在一些差异,但匹配次数多于非匹配次数。

Call 1: product2 <-- 
Call 2: product2 <--
Call 3: product2 <-- this is a common scenario where there seems to be no randomness

2 个答案:

答案 0 :(得分:2)

试试这个:

        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> @this)
        {
            if (@this.Count() <= 1) return @this;
            Random rand = new Random();
            return @this.Select(x => new { x = x, r = rand.Next() }).OrderBy(x => x.r).Select(x => x.x);
        }

答案 1 :(得分:-1)

我这样做随机排序:

().OrderBy(p => Guid.NewGuid())

所以每个项目都有一个独特且随机的Guid,在每次通话中你都可以获得完全不同的IEnumerable排序。

在你的情况下,这是我将如何做,没有任何扩展方法:

public IEnumerable<PriceQuote> BestQuote(int take = 0)
{
    var q = Quotes.Where(x => x.TotalRepayable == MinPrice)
        .OrderBy(x => Guid.NewGuid())
        .ThenByDescending(x => x.ProductDetail.Product.IsSponsored);

    return take == 0 ? q : q.Take(take);
}

我不确定订单应该在哪个顺序,也许两者都相同,但如果上面的代码不起作用,你可以尝试这样:

public IEnumerable<PriceQuote> BestQuote(int take = 0)
{
    var q = Quotes.Where(x => x.TotalRepayable == MinPrice)
        .OrderBy(x => x.ProductDetail.Product.IsSponsored)
        .ThenByDescending(x => Guid.NewGuid());

    return take == 0 ? q : q.Take(take);
}

修改

感谢@Maarten,这是使用扩展程序的最终解决方案:

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> @this)
{
    if (@this.Count() <= 1) return @this;
    return @this.Select(x => new { x = x, g = Guid.NewGuid() }).OrderBy(x => x.g).Select(x => x.x);
}

如果您的列表中有一些项目,那么使用我的第一个或最后一个解决方案并不重要。但正如@ Maarteen在评论中警告的那样,可能会有更多不必要的Guids而不是项目&#39;计数。并且与多个项目进行多次比较可能是一个问题。 所以我把@ jdweng的答案和我的答案结合起来。