【问题标题】:Order a list by a field then by random按字段排序列表,然后随机排序
【发布时间】:2015-06-01 17:29:26
【问题描述】:
var r = new Random();
var orderedList = aListOfPeople.OrderBy(x => x.Age).ThenBy(x => r.Next());

按“年龄”然后随机排序列表的更好方法是什么?

我的目标是确保如果 PersonA 年龄 = PersonB 年龄,则 PersonA 在某些情况下会排在第一位,而 PersonB 在其他情况下会排在第一位。

【问题讨论】:

  • 随机排序不是排序,而是洗牌。我认为按年龄分组,然后改组可能是更好的方法。
  • @MattBurland 所以我的目标是“排序”然后“洗牌”只有相等的值
  • @Max,请参阅此随机播放:stackoverflow.com/a/375446/961113
  • 洗牌似乎并不难,但我想保留列表的顺序。我只想洗牌相等的值。我无法理解它。
  • 如果你只是按Age排序,那么你应该得到你想要的结果。如果Age 的值相等,则无法保证您获得它们的顺序。

标签: c# linq sorting random


【解决方案1】:

使用 SQL 中的技术

var orderedList = aListOfPeople.OrderBy(x => x.Age).ThenBy(x => Guid.NewGuid());

警告:这不是真正的随机,只是一种懒惰的方法,请参阅问题的评论部分

【讨论】:

    【解决方案2】:

    最简单的答案是洗牌然后排序。如果您使用稳定排序,则排序必须保留等键值的打乱顺序。但是,即使不稳定的排序会扰乱您的随机播放,我也想不出任何合理的情况可以取消对等键值的随机播放。

    不过,这可能有点低效......

    如果您担心碰撞,我可能会假设您的年龄是整数年龄。在这种情况下,您可能会考虑基数排序(256 个 bin 对任何活着的人来说都足够了),当需要将这些 bin 重新缝合在一起时,您可以在将每个 bin 中的元素附加到列表时以随机顺序删除它们.

    如果您的列表已经按年龄排序,并且您只想就地洗牌,那么您只需要遍历列表,计算以下元素中有多少相等,执行对这么多元素进行就地洗牌,然后前进到下一个不匹配的元素并重复。

    我认为后者应该是这样的(我会用 C 编写,因为我不懂 C#):

    int i = 0;
    while (i < a.length) {
      int j;
      while (a[j] == a[i] && j < a.length) j++;
      while (i + 1 < j) {
        int k = random(j - i) + i;
        swap(a[i], a[k]);
        i++;
      }
      i++;
    }
    

    还没有测试过,但应该给出大致的想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-03
      • 2022-11-18
      • 2020-01-29
      • 2018-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      相关资源
      最近更新 更多