筛选元组列表

jez*_*ael 2 python tuples group-by list

我有清单:

print (L)
[('bar', 'one'), ('bar', 'two'), ('baz', 'one'), 
 ('baz', 'two'), ('foo', 'one'), ('qux', 'one'), 
 ('qux', 'two'), ('oof', 'two'), ('oof', 'one'), ('oof', 'three')]
Run Code Online (Sandbox Code Playgroud)

我希望通过元组中的第一个元素进行分组,并过滤​​包含one和two作为第二个元素的所有元组.

所以需要过滤掉('oof', 'two'),('foo', 'one')因为只有一个元素foo和3个元素oof.

预期输出 - 对于每个第一个元素bar,baz第二个是one和two,长度为2:

print(L1)   
[('bar', 'one'), ('bar', 'two'), 
 ('baz', 'one'), ('baz', 'two'), 
 ('qux', 'one'), ('qux', 'two')]
Run Code Online (Sandbox Code Playgroud)

我尝试:

L = [b in ['one','two'] for a,b in L]
print (L)
[True, True, True, True, True, True, True, True]
Run Code Online (Sandbox Code Playgroud)

什么是好/ pythonic解决方案呢?

Ara*_*Fey 5

这是一个解决方案groupby:

import itertools, operator

# group the tuples by the first element
result = itertools.groupby(sorted(L), key=operator.itemgetter(0))
# convert the groups to lists
result = [list(group) for _, group in result]
# filter out those lists that don't contain exactly "one" and "two"
result = [group for group in result if set(y for x, y in group) == {'one', 'two'}]
# flatten the nested list into a list of tuples
result = [x for group in result for x in group]

print(result)
Run Code Online (Sandbox Code Playgroud)

请注意,这并不关心重复的元组:

L = [('bar', 'one'), ('bar', 'two'), ('bar', 'two')]
# result = [('bar', 'one'), ('bar', 'two'), ('bar', 'two')]
Run Code Online (Sandbox Code Playgroud)

如果你不想在输出中使用这些,你可以重写过滤条件(第二列表理解),如下所示:

result = [group for group in result if
             set(y for x, y in group) == {'one', 'two'} and len(group) == 2]
Run Code Online (Sandbox Code Playgroud)