Python:不冗余的列表项之间的比较

时间:2015-01-24 19:45:46

标签: python for-loop optimization comparison graph-algorithm

假设我有一个嵌套在dict键中的列表。所以像这样:

d = {'people':['John', 'Carry', 'Joe', 'Greg', 'Carl', 'Gene']}

我想比较列表中的人员,以便我可以创建一个图表,连接以相同的第一个字母开头的名称。

我想出了一个嵌套的for循环来尝试解决这个问题:

for subject in d.keys():
        for word1 in d[people]:
            for word2 in d[people]:
                if word1[0] == word2[0]:
                    g.connectThem(word1,word2)

但嵌套的for循环可能会变得多余,因为它会使两次相同的比较。有没有办法让它在比较方面没有冗余?

2 个答案:

答案 0 :(得分:2)

您可以使用itertools.combinations

迭代对
for pair in itertools.combinations(d['people'], 2):
    first, second = pair
    if first[0] == second[0]:
        g.connectThem(first, second)

这些是从combinations

生成的对
[('John', 'Carry'), ('John', 'Joe'), ('John', 'Greg'), ('John', 'Carl'), ('John', 'Gene'),
 ('Carry', 'Joe'), ('Carry', 'Greg'), ('Carry', 'Carl'), ('Carry', 'Gene'),
 ('Joe', 'Greg'), ('Joe', 'Carl'), ('Joe', 'Gene'),
 ('Greg', 'Carl'), ('Greg', 'Gene'),
 ('Carl', 'Gene')]

请注意,您没有重复的问题(通过颠倒对的顺序) 假设您的connectThem函数有效,这应该会产生您想要的行为。

答案 1 :(得分:1)

如果你想将列表中的人物相互比较,以便我可以创建一个图表,连接以相同的第一个字母开头的名称。然后使用dict和单个传递d["people"]您使用名字的第一个字母作为键,因此解决方案为0(n),并且明显比二次方更有效,因为所有组合都会产生大多数不必要的配对:

d = {"people":['John', 'Carry', 'Joe', 'Greg', 'Carl', 'Gene']}

from collections import defaultdict

my_d = defaultdict(list)

for v in d["people"]:
    my_d[v[0]].append(v)
print(my_d)
defaultdict(<type 'list'>, {'C': ['Carry', 'Carl'], 'J': ['John', 'Joe'], 'G': ['Greg', 'Gene']})

现在,您可以通过迭代my_d的值,将具有常用名字的完整名称列表传递给要添加到图表的方法。

如果要创建列表长度为&gt;的人员组合。 2然后你可以使用原始列表保存多个不必要的组合。它只会结合你想要的实际名称。

因此,要处理重复的名称,只能使用具有共同首字母的名称进行组合,并且只考虑具有链接的组,即具有非唯一首字母的名称:

from collections import defaultdict
# store all names in groups, grouped by common first letter in names
my_d = defaultdict(set)

for v in d["people"]:
     # 0(1) set lookup avoids adding names twice
    if v not in my_d[v[0]]:
        my_d[v[0]].add(v)


from itertools import combinations

for group in my_d.itervalues():
    # two elements are a combination
    if len(group) == 2:
        g.connectThem(group[0],group[1])   
    # ignore uniques names ?     
    elif len(group) > 2:
        for n1,n2  in combinations(group,2):            
            g.connectThem(n1 ,n2)

根本没有使用itertools我们可以看到,因为我们的线性传递创建了一个分组的dict,我们可以简单地遍历out dict中的每个值列表并创建唯一的配对:

for group in my_d.itervalues():
    for ind, n1 in enumerate(group):
        for n2 in group[ind+1:]:
            print(n1,n2)
('Carry', 'Carl')
('John', 'Joe')
('Greg', 'Gene')