组装具有共同中心元素的列表

时间:2016-05-11 15:46:34

标签: python python-2.7 python-3.x

我正在创建所有可能的排列,包括从0到给定数字的三个元素:

for i in itertools.permutations(range(len(atoms)), 3):
    if i[0] < i[-1]:
        angles = list(i)

条件避免在我的列表上同时具有(0,1,2)和(2,1,0)“角度”,这已经很棒了。现在,我需要将此列表分成由具有相同中心元素的“角度”组成的较小组。 通过这种方式,我有:

A = ([0, 1, 2], [0, 1, 3], [3, 1, 4])...
B = ([0, 2, 3], [0, 2, 4], [3, 2, 4])...

等等。

你能帮帮我吗?

4 个答案:

答案 0 :(得分:2)

您可以使用defaultdict对排列进行分组:

from collections import defaultdict

angles = defaultdict(list)

for i in itertools.permutations(range(len(atoms)), 3):
    if i[0] < i[-1]:
        angles[i[1]].append(i)

如果len(atoms)为4,那么您将获得以下结果:

defaultdict(<type 'list'>, {
    0: [(1, 0, 2), (1, 0, 3), (2, 0, 3)], 
    1: [(0, 1, 2), (0, 1, 3), (2, 1, 3)], 
    2: [(0, 2, 1), (0, 2, 3), (1, 2, 3)], 
    3: [(0, 3, 1), (0, 3, 2), (1, 3, 2)]
})

答案 1 :(得分:1)

itertools.groupby函数可用于创建包含相同中心元素的列表,但您必须先对列表进行排序,以便具有相同中心元素的排列彼此相邻。为此,您需要向sortgroupby传递一个查看中心元素的关键函数。一种方法是这样的:

def keyfunc(s):
    return s[1]

或者,作为一个lambda:

keyfunc = lambda s: s[1]

或者您可以使用itemgetter模块中的operator,该模块简洁且明显快于使用lambdadef功能。

以下代码基于您的代码,但它会在列表推导中创建初始列表。然后它将组放在字典中,中心元素为dict键。

from itertools import permutations, groupby
from operator import itemgetter

atoms = 'abcd'
perms = permutations(range(len(atoms)), 3)
angles = [list(u) for u in perms if u[0] < u[-1]]

keyfunc = itemgetter(1)

angles.sort(key=keyfunc)
print(angles)

groups = {k: list(g) for k, g in groupby(angles, keyfunc)}
print(groups)

<强>输出

[[1, 0, 2], [1, 0, 3], [2, 0, 3], [0, 1, 2], [0, 1, 3], [2, 1, 3], [0, 2, 1], [0, 2, 3], [1, 2, 3], [0, 3, 1], [0, 3, 2], [1, 3, 2]]
{0: [[1, 0, 2], [1, 0, 3], [2, 0, 3]], 1: [[0, 1, 2], [0, 1, 3], [2, 1, 3]], 2: [[0, 2, 1], [0, 2, 3], [1, 2, 3]], 3: [[0, 3, 1], [0, 3, 2], [1, 3, 2]]}

答案 2 :(得分:1)

虽然上述答案为更一般的问题提供了出色的解决方案,但只需3个元素就可以选择列表理解就足够了。

atoms = [0, 1, 2, 3]

angles = [[(a, b, c) for i, a in enumerate(atoms, start=1) if a != b
    for c in atoms[i:] if c != b] for b in atoms]


# [[(1, 0, 2), (1, 0, 3), (2, 0, 3)],
#  [(0, 1, 2), (0, 1, 3), (2, 1, 3)],
#  [(0, 2, 1), (0, 2, 3), (1, 2, 3)],
#  [(0, 3, 1), (0, 3, 2), (1, 3, 2)]]

它比我的机器上的排列+ groupby方法快约40%。

答案 3 :(得分:0)

您可以考虑itertools.groupby

from itertools import groupby, permutations

perms = filter(lambda x: x[0] < x[-1], permutations(range(4), 3))
key = lambda x: x[1]  # sort and group by second element
angles = [list(g) for k, g in groupby(sorted(perms, key=key), key=key)]
# here, any comprehension can be used, e.g.
# angles = {k: list(g) for k, g in groupby(sorted(perms, key=key), key=key)}
# will produce the dict from @niemmi's answer

>>> angles
[
    [(1, 0, 2), (1, 0, 3), (2, 0, 3)], 
    [(0, 1, 2), (0, 1, 3), (2, 1, 3)], 
    [(0, 2, 1), (0, 2, 3), (1, 2, 3)], 
    [(0, 3, 1), (0, 3, 2), (1, 3, 2)]
]