查找具有共同元素的元组

1 投票
3 回答
1941 浏览
提问于 2025-04-17 12:12

假设我有一组包含人名的元组。我想找出所有有相同姓氏的人,但不包括那些没有和其他人共享姓氏的人:

# input
names = set([('John', 'Lee'), ('Mary', 'Miller'), ('Paul', 'Ryan'), 
             ('Bob', 'Ryan'), ('Tina', 'Lee'), ('Bob', 'Smith')])

# expected output
{'Lee': ['Tina', 'John'], 'Ryan': ['Bob', 'Paul']} # or similar

这是我现在使用的方法

def find_family(names):
    result = {}

    try:
        while True:
            name = names.pop()
            if name[1] in result:
                result[name[1]].append(name[0])
            else:
                result[name[1]] = [name[0]]
    except KeyError:
        pass

    return dict(filter(lambda x: len(x[1]) > 1, result.items()))

这个方法看起来很复杂而且效率不高。有没有更好的办法呢?

3 个回答

1

与其使用while循环,不如用for循环(或者类似的结构)来遍历集合的内容(顺便可以把元组拆开):

for firstname, surname in names:
    # do your stuff

你可能想在循环的主体中使用一个defaultdict或者OrderedDict(http://docs.python.org/library/collections.html)来存放你的数据。

1
>>> names = set([('John', 'Lee'), ('Mary', 'Miller'), ('Paul', 'Ryan'), 
...              ('Bob', 'Ryan'), ('Tina', 'Lee'), ('Bob', 'Smith')])

你可以通过一个循环很简单地得到一个字典,这个字典里包含了所有人的信息,键是他们的姓氏。

>>> families = {}
>>> for name, lastname in names:
...   families[lastname] = families.get(lastname, []) + [name]
... 
>>> families
{'Miller': ['Mary'], 'Smith': ['Bob'], 'Lee': ['Tina', 'John'], 'Ryan': ['Bob', 'Paul']}

接着,你只需要用条件 len(names) > 1 来过滤这个字典。这个过滤可以用一种叫“字典推导式”的方法来完成。

>>> filtered_families = {lastname: names for lastname, names in families.items() if len(names) > 1}
>>> filtered_families
{'Lee': ['Tina', 'John'], 'Ryan': ['Bob', 'Paul']}
4

defaultdict 可以用来简化代码:

from collections import defaultdict

def find_family(names):
    d = defaultdict(list)
    for fn, ln in names:
        d[ln].append(fn)
    return dict((k,v) for (k,v) in d.items() if len(v)>1)

names = set([('John', 'Lee'), ('Mary', 'Miller'), ('Paul', 'Ryan'), 
             ('Bob', 'Ryan'), ('Tina', 'Lee'), ('Bob', 'Smith')])
print find_family(names)

这段代码的输出是:

{'Lee': ['Tina', 'John'], 'Ryan': ['Bob', 'Paul']}

撰写回答