以相同的方式随机播放两个列表

时间:2012-03-14 23:09:14

标签: c# ienumerable shuffle

我想要洗牌两个列表,以便它们以相同的方式进行洗牌(前提是我有一个方法Shuffle(列表列表),它会混洗一个列表。

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

结果:
答:C,B,D,A
B:Y,X,Z,W

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

3 个答案:

答案 0 :(得分:8)

选项1:zip,shuffle,解压缩

要扩展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在给定相同的随机数序列时做同样的事情,这将以相同的方式对两个列表进行洗牌。

答案 1 :(得分:5)

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的数组进行混洗来进行排列。如果将相同的排列数组应用于两个不同的列表,那么您将获得两个不同列表的相同“shuffle”。有意义吗?

答案 2 :(得分:2)

获取一个新的整数列表,其内容是[0, length of A and B)中的所有数字。这些对应于列表中元素的索引。洗牌那个清单。现在使用混洗索引来置换两个原始列表。