改善两个相关列表的更好方法

时间:2012-08-01 18:10:21

标签: python list shuffle

有没有更好的方法随机洗牌两个相关的列表而不打破其他列表中的对应关系?我在numpy.arrayc#中找到了相关问题,但不完全相同。

首次尝试时,会有一个简单的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]

发现它有点尴尬。它还需要一个额外的列表。

7 个答案:

答案 0 :(得分:40)

鉴于问题中展示的关系,我将假设列表长度相同,list1[i]对应任何索引list2[i] i。有了这个假设,改组列表就像改组索引一样简单:

对于Python2.x:

from random import shuffle
# Given list1 and list2

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

对于Python 3.x:

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])

答案 1 :(得分:20)

如果您愿意再安装一些软件包:

所需物品: NumPy(> = 1.6.1), SciPy(> = 0.9)。

pip install -U scikit-learn

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

答案 2 :(得分:6)

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

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

答案 3 :(得分: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]

答案 4 :(得分:1)

使用numpy快速回答请参考here
你可以使用

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]

答案 5 :(得分:0)

我不确定我是否在这里遗漏了一些东西,但看起来你只是在拖拽其中一个列表,而另一个则重新排列以匹配第一个列表的顺序。所以你拥有的是最好的方法,而不是让它变得更复杂。如果你想要复杂的路线你可以随便洗牌1列表并使用未洗牌的列表在洗牌列表中进行查找并以这种方式重新排列。最后,您最终会得到与开始时相同的结果。为什么创建第三个列表是个问题?如果您真的想要回收列表,那么您可以简单地将列表b替换为您用于列表c的内容,然后将其分离回a和b。

答案 6 :(得分:0)

您可以在末尾解压缩以减轻尴尬吗?

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