我想改组这个列表:
[[1, 'A'], [2, 'A'], [6, 'B'], [3, 'B'], [4, 'C'], [5, 'C'], [7, 'F']]
Run Code Online (Sandbox Code Playgroud)
但是我需要由子列表第二个元素标识的组保持在一起,以便无序列表看起来像这样:
[[6, 'B'], [3, 'B'], [7, 'F'], [1, 'A'], [2, 'A'], [4, 'C'], [5, 'C']]
Run Code Online (Sandbox Code Playgroud)
所有“B”、“F”、“A”和“C”子列表都放在一起的地方。
我猜测使用 shuffle 和 groupby 的组合可以解决问题,但我不知道从哪里开始。任何想法将不胜感激!
items = [[1, 'A'], [2, 'A'], [6, 'B'], [3, 'B'], [4, 'C'], [5, 'C'], [7, 'F']]
import itertools, operator, random
groups = [list(g) for _, g in itertools.groupby(items, operator.itemgetter(1))]
random.shuffle(groups)
shuffled = [item for group in groups for item in group]
print(shuffled)
Run Code Online (Sandbox Code Playgroud)
打印例如:
[[4, 'C'], [5, 'C'], [1, 'A'], [2, 'A'], [7, 'F'], [6, 'B'], [3, 'B']]
Run Code Online (Sandbox Code Playgroud)
给每个组一个随机数并以此排序。子列表保持在一起是因为 Python 的排序是稳定的。
多年后更新:使用defaultdict看起来更好,并且只为每组生成一个随机数,而不是为每个元素生成一个:
from random import random
from collections import defaultdict
r = defaultdict(random)
items.sort(key=lambda item: r[item[1]])
Run Code Online (Sandbox Code Playgroud)
作为挤压oneliner:
items.sort(key=lambda i, r=defaultdict(random): r[i[1]])
Run Code Online (Sandbox Code Playgroud)
回到原来的答案:
items = [[1, 'A'], [2, 'A'], [6, 'B'], [3, 'B'], [4, 'C'], [5, 'C'], [7, 'F']]
import random
r = {b: random.random() for a, b in items}
items.sort(key=lambda item: r[item[1]])
print(items)
Run Code Online (Sandbox Code Playgroud)
打印例如:
[[6, 'B'], [3, 'B'], [4, 'C'], [5, 'C'], [7, 'F'], [1, 'A'], [2, 'A']]
Run Code Online (Sandbox Code Playgroud)
这两行可以合并,然后你就没有那个额外的变量在后面飞来飞去。
items.sort(key=lambda item, r={b: random.random() for a, b in items}: r[item[1]])
Run Code Online (Sandbox Code Playgroud)