Python 洗牌两个相关列表的更好方法

Python 洗牌两个相关列表的更好方法,python,list,shuffle,Python,List,Shuffle,有没有更好的方法可以随机洗牌两个相关的列表,而不破坏它们在另一个列表中的对应关系?我在numpy.array和c#中找到了相关的问题,但不完全相同 作为第一次尝试,一个简单的zip技巧可以: import random a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] b = [2, 4, 6, 8, 10] c = zip(a, b) random.shuffle(c) a = [e[0] for e in c] b = [e[1] for e in

有没有更好的方法可以随机洗牌两个相关的列表,而不破坏它们在另一个列表中的对应关系?我在
numpy.array
c#
中找到了相关的问题,但不完全相同

作为第一次尝试,一个简单的
zip
技巧可以:

import random
a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
b = [2, 4, 6, 8, 10]
c = zip(a, b)
random.shuffle(c)
a = [e[0] for e in c]
b = [e[1] for e in c]
print a
print b
它将获得以下输出:

[[1, 2], [7, 8], [3, 4], [5, 6], [9, 10]]
[2, 8, 4, 6, 10]

只是觉得有点尴尬。而且它还需要一个额外的列表。

考虑到问题中演示的关系,我将假设列表的长度相同,
list1[I]
对应于任何索引
I
list2[I]
。有了这一假设,对列表进行无序排列就像对索引进行无序排列一样简单:

 from random import shuffle
 # Given list1 and list2

 list1_shuf = []
 list2_shuf = []
 index_shuf = list(range(len(list1)))
 shuffle(index_shuf)
 for i in index_shuf:
     list1_shuf.append(list1[i])
     list2_shuf.append(list2[i])

如果你必须经常这样做,你可以考虑通过改组索引列表来添加一个间接级别。

Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import random
>>> a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
>>> b = [2, 4, 6, 8, 10]
>>> indexes = range(len(a))
>>> indexes
[0, 1, 2, 3, 4]
>>> random.shuffle(indexes)
>>> indexes
[4, 1, 2, 0, 3]
>>> for index in indexes:
...     print a[index], b[index]
...
[9, 10] 10
[3, 4] 4
[5, 6] 6
[1, 2] 2
[7, 8] 8

我不确定这里是否遗漏了什么,但看起来您只是在洗牌其中一个列表,而另一个列表被重新排列以匹配第一个列表的顺序。因此,你所拥有的是最好的方法来做到这一点,而不会使它变得更复杂。如果你想走一条复杂的路线,你只需将1个列表洗牌,然后使用非洗牌列表在洗牌列表中进行查找,并以这种方式重新排列它。最后,你会得到和你开始时一样的结果。为什么创建第三个列表是个问题?如果你真的想回收列表,那么你可以简单地用你在列表c中使用的替换列表b,然后稍后将其分离回a和b

使用numpy的快速答案请参考:
你可以用

p = numpy.random.permutation(len(a))
为两个列表创建一个新的索引列表,并使用它对它们进行重新排序

在您的场景中:

In [61]: a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
In [62]: b = [2, 4, 6, 8, 10]
In [63]: import numpy as np
In [64]: a_ar, b_ar = np.array(a), np.array(b)
In [65]: p = np.random.permutation(len(a))
In [66]: a, b = a_ar[p].tolist(), b_ar[p].tolist()
In [68]: a
Out[68]: [[3, 4], [7, 8], [5, 6], [1, 2], [9, 10]]
In [69]: b
Out[69]: [4, 8, 6, 2, 10]

如果您愿意再安装几个软件包:

请求: NumPy(>=1.6.1), SciPy(>=0.9)

pip安装-U scikit学习

from sklearn.utils import shuffle
list_1, list_2 = shuffle(list_1, list_2)

到目前为止,所有解决方案都创建了新的列表以解决此问题。如果列表a和b很长,您可能需要将它们洗牌。为此,您需要一个函数,如:

import random

def shuffle(a,b):
    assert len(a) == len(b)
    start_state = random.getstate()
    random.shuffle(a)
    random.setstate(start_state)
    random.shuffle(b)

a = [1,2,3,4,5,6,7,8,9]
b = [11,12,13,14,15,16,17,18,19]
shuffle(a,b)
print(a) # [9, 7, 3, 1, 2, 5, 4, 8, 6]
print(b) # [19, 17, 13, 11, 12, 15, 14, 18, 16]

你可以在结尾做一个解压来限制一点尴尬吗

import numpy as np
list1 = [1,2,3]
list2 = [4,5,7]
list_zipped = list(zip(list1,list2))
np.random.shuffle(list_zipped)
list1,list2 = zip(*z) #unzipping

您也可以使用
zip
解压列表:
a,b=zip(*c)
我通常也不推荐需要保留一组并行列表的程序设计。只需保留1个列表。创建某种类或东西来统一您的数据。如果您想通过
numpy
来完成这类工作,这里有一个很好的解决方案:作为列表理解的爱好者:list1_shuf=[list1[i]for i in index_shuf]@kojiro:没关系:nappend_ops+nappend_ops=n*(append_ops+append_ops)=2*n*append_ops