查找具有共同元素的元组
假设我有一组包含人名的元组。我想找出所有有相同姓氏的人,但不包括那些没有和其他人共享姓氏的人:
# 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']}