首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >尝试获取随机排序顺序

尝试获取随机排序顺序
EN

Stack Overflow用户
提问于 2017-01-17 20:05:07
回答 2查看 613关注 0票数 3

使用C#/Asp.Net。

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

我有一个报价列表-有时有多个产品具有相同的价格。

此外,一些结果是附属的(赞助的),所以我们也需要优先考虑这些结果。

下面是调用的方法:

代码语言:javascript
复制
    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)再次排序,然后根据需要获取多少结果。

我首先将它们打乱,以获得一个随机的顺序-从随机列表中,我想首先获得赞助项目-然后,如果需要的话,用非赞助项目填充空格。理论上,赞助和非赞助的每次都是随机顺序的。

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
    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次调用的顺序都是相同的。情况并不总是这样--有一些差异,但匹配的比不匹配的多。

代码语言:javascript
复制
Call 1: product2 <-- 
Call 2: product2 <--
Call 3: product2 <-- this is a common scenario where there seems to be no randomness
EN

回答 2

Stack Overflow用户

发布于 2017-01-17 20:25:30

试试这个:

代码语言:javascript
复制
        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);
        }
票数 2
EN

Stack Overflow用户

发布于 2017-01-17 20:35:07

我像这样做随机排序:

代码语言:javascript
复制
().OrderBy(p => Guid.NewGuid())

因此,每个项目都有一个唯一和随机的Guid,在每次调用中,您可以获得完全不同的排序IEnumerable。

在你的例子中,我是这样做的,没有任何扩展方法:

代码语言:javascript
复制
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);
}

我不确定顺序应该是什么,也许两者都是相同的,但如果上面的代码不起作用,你可以尝试这样做:

代码语言:javascript
复制
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,这是使用扩展的最终解决方案:

代码语言:javascript
复制
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在评论中警告的那样,可能会有更多不必要的Guid,而不是项目的数量。这可能是一个问题,对许多项目进行多次比较。所以我把@jdweng的答案和我的结合起来。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41696666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档