【问题标题】:Shuffle two lists in the same way以相同的方式随机播放两个列表
【发布时间】:2012-03-14 23:09:14
【问题描述】:

我想打乱两个列表,使它们以相同的方式打乱(前提是我有一个方法 Shuffle(List list) 打乱一个列表。

List<ObjX> listA = new List<ObjX>() { A, B, C, D };
List<ObjX> listB = new List<ObjX>() { W, X, Y, Z };
ShuffleTwoLists(listA , listB )

结果:
A:C、B、D、A
B:Y、X、Z、W

有没有在 C# 中快速实现 ShuffleTwoLists(listA , listB) 的方法?

【问题讨论】:

  • 压缩、随机播放、解压缩

标签: c# ienumerable shuffle


【解决方案1】:

选项 1:压缩、随机播放、解压缩

扩展 Marcelo 的评论,并假设您不介意创建 列表而不是改组 现有 列表:

var zipped = listA.Zip(listB, (a, b) => new { a, b } ).ToList();
Shuffle(zipped);
var newListA = zipped.Select(pair => pair.a).ToList();
var newListB = zipped.Select(pair => pair.b).ToList();

选项 2:随机排列索引

用代码扩展 MAK 的答案:

var indexes = Enumerable.Range(0, listA.Count).ToList();
Shuffle(indexes);
var newListA = indexes.Select(index => listA[index]).ToList();
var newListB = indexes.Select(index => listB[index]).ToList();

当然,这两种方法都可以改变原始列表,但需要做更多的工作。

选项 3:使用相同的随机种子随机排列两个列表

我个人喜欢将Random(或其他)传递给需要它们的方法/类,而不是创建新的。所以我会给我的Shuffle 一个Random 参数。它避免了各种问题,并且很好地表达了依赖关系。您可以通过使用相同的种子创建两个 Random 实例来利用这一点:

int seed = existingRandom.Next();
Shuffle(listA, new Random(seed));
Shuffle(listB, new Random(seed));

假设Shuffle 在给定相同的随机数序列时做同样的事情,这将以相同的方式打乱两个列表。

【讨论】:

  • @MarceloCantos:虽然我希望你不会介意我使用你的想法 :)
  • +1。几分钟后,我想回圈并发布代码,但工作阻碍了。谢谢。
  • 我不太喜欢选项 3。一个缺点是你只能得到 20 亿个不同的排列。而 IMO 它是最反 DI 的,因为它创建了自己的 Random 实例,这不允许注入 Random 的不同实现,例如因为你有更好的性能或质量。 |但我承认这些只是我后来发现的不喜欢的理由。即使没有这些原因,我也会不喜欢它,因为我觉得它不直观。
  • @CodeInChaos:您可以通过传入Func&lt;long, IRandom&gt; 或类似的东西(对于一些合适的IRandom 接口)来缓解这两种情况,这将使用相关的种子随机给出。 (您需要做一些工作才能将 64 位用于 Random 本身的种子,可能会创建两个 Random 实例并组合 rseult 或类似的东西。)
【解决方案2】:

Jon 的所有技巧都很好。另一种技术是:

class PermutedList<T> 
{
    private readonly IList<T> underlying;
    private readonly IList<int> permutation;
    public T this[int i]
    {
        get { return underlying[permutation[i]]; }
    }
    ...

也就是说,围绕底层列表创建一个包装类。通过将数字从 0 到 n-1 的数组改组来进行排列。如果您将相同的排列数组应用于两个不同的列表,那么您将获得两个不同列表的相同“洗牌”。有意义吗?

【讨论】:

  • 为了增加疯狂,也添加 setter,把每个人都搞糊涂了 :) (我个人非常喜欢我的第三个解决方案,因为我已经想到了它......强调Random的依赖注入(如果没有别的)
  • +1 - 在问题中提出的情况下,我喜欢这种方法(只有int 值),因为它的行为类似于 C++ 中的指针集合,但我想知道是否会有任何如果permutation 不是ints 的集合,则受益。
【解决方案3】:

获取一个新的整数列表,其内容是[0, length of A and B)中的所有数字。这些对应于列表中元素的索引。随机播放该列表。现在使用打乱的索引排列两个原始列表。

【讨论】:

  • 我正在寻找一个通用的解决方案。我将更新示例。
  • @Gjorgji:这一个通用的解决方案。这里的int 值不是原始列表中的值——它们是索引。原始列表可以是字符串、Guid 等等。
猜你喜欢
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-23
  • 2020-12-10
  • 2011-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多