【问题标题】:How to shuffle an array while grouping equal values together?如何在将相等的值分组在一起时对数组进行洗牌?
【发布时间】:2021-07-06 02:12:18
【问题描述】:

假设我有一个这样的数组。

int[] arr = {1,2,3,4,4,5,6,7,8,8,8,1};

我如何洗牌,但所有的值都相等?

随机播放后的示例预期输出:

3,1,1,8,8,8,7,2,4,4,6,5

【问题讨论】:

  • 你要处理{1, 1, 2, 2, 1, 1, 2, 2}这样的数组吗?如果是这样,{2, 2, 1, 1, 2, 2, 1, 1} 是有效的输出吗?还是 {1, 1, 1, 1, 2, 2, 2, 2}{2, 2, 2, 2, 1, 1, 1, 1} 是唯一有效的输出?
  • 只有 1,1,1,1,2,2,2,2 和 2,2,2,2,1,1,1,1

标签: c# random fisher-yates-shuffle


【解决方案1】:

你可以这样做:

  • 查找数组中的唯一值以及每个值出现的次数。将计数存储在字典中,例如 counts
  • 使用洗牌算法(例如 Fisher-Yates)对唯一值进行洗牌。
  • 对于洗牌数组中的每个值v,将v 写入输出数组counts[v] 次。

【讨论】:

    【解决方案2】:
    var rng = new Random();    
    arr = arr
        .GroupBy(i => i)
        .OrderBy(g => rnd.Next())
        .SelectMany(g => g)
        .ToArray();
    

    【讨论】:

    • 什么是rnd(请编辑您的代码以显示此内容)?请提供有关您的答案如何工作的更多详细信息。我同意这可能是解决这个问题的最巧妙的方法(尽管不使用 OP 要求的洗牌算法),但 OP/未来的读者可能需要更多的解释。
    • 只有在保证每个组元素只调用一次g => rnd.Next() 函数时才有效。虽然这是真的(至少在 .NET 5 中),但此解决方案依赖于未记录的行为。
    • 一般来说,在使用 LINQ 时,您不应该依赖对 lambda 函数的调用次数、调用它们的参数或调用的顺序。看到这个:github.com/dotnet/runtime/issues/31554
    • @JosephDaSilva 为什么只有保证每个组元素调用一次它才有效?如果多次调用它会出现什么问题?
    • @Llama 如果键选择器被多次调用并且每次都返回不同的随机值,那么你有一个不一致的比较函数(例如,它可能会在调用一次时报告x < y和@987654327 @第二次调用时)。当给定不一致的比较函数时,某些排序算法可能会抛出错误或进入无限循环。 ericlippert.com/2011/01/31/bad-comparisons-part-four
    猜你喜欢
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多