从 Python 中的列表中删除列表子集的最快方法
Fastest way to remove subsets of lists from a list in Python
假设我有一个如下所示的列表列表(实际列表要长得多):
fruits = [['apple', 'pear'],
['apple', 'pear', 'banana'],
['banana', 'pear'],
['pear', 'pineapple'],
['apple', 'pear', 'banana', 'watermelon']]
在这种情况下,列表 ['banana', 'pear']
、['apple', 'pear']
和 ['apple', 'pear', 'banana']
中的所有项目都包含在列表 ['apple', 'pear', 'banana', 'watermelon']
中(项目的顺序无关紧要) ),所以我想删除 ['banana', 'pear']
、['apple', 'pear']
和 ['apple', 'pear', 'banana']
,因为它们是 ['apple', 'pear', 'banana', 'watermelon']
的子集。
我目前的解决方案如下所示。我首先使用 ifilter
和 imap
为每个列表可能具有的超集创建生成器。然后对于那些确实有超集的情况,我使用 compress
和 imap
来删除它们。
from itertools import imap, ifilter, compress
supersets = imap(lambda a: list(ifilter(lambda x: len(a) < len(x) and set(a).issubset(x), fruits)), fruits)
new_list = list(compress(fruits, imap(lambda x: 0 if x else 1, supersets)))
new_list
#[['pear', 'pineapple'], ['apple', 'pear', 'banana', 'watermelon']]
我想知道是否有更有效的方法来做到这一点?
我不知道它是否更快但这更容易阅读(无论如何对我来说):
sets={frozenset(e) for e in fruits}
us=set()
while sets:
e=sets.pop()
if any(e.issubset(s) for s in sets) or any(e.issubset(s) for s in us):
continue
else:
us.add(e)
更新
速度很快。更快的方法是使用 for
循环。检查时间:
fruits = [['apple', 'pear'],
['apple', 'pear', 'banana'],
['banana', 'pear'],
['pear', 'pineapple'],
['apple', 'pear', 'banana', 'watermelon']]
from itertools import imap, ifilter, compress
def f1():
sets={frozenset(e) for e in fruits}
us=[]
while sets:
e=sets.pop()
if any(e.issubset(s) for s in sets) or any(e.issubset(s) for s in us):
continue
else:
us.append(list(e))
return us
def f2():
supersets = imap(lambda a: list(ifilter(lambda x: len(a) < len(x) and set(a).issubset(x), fruits)), fruits)
new_list = list(compress(fruits, imap(lambda x: 0 if x else 1, supersets)))
return new_list
def f3():
return filter(lambda f: not any(set(f) < set(g) for g in fruits), fruits)
def f4():
sets={frozenset(e) for e in fruits}
us=[]
for e in sets:
if any(e < s for s in sets):
continue
else:
us.append(list(e))
return us
if __name__=='__main__':
import timeit
for f in (f1, f2, f3, f4):
print f.__name__, timeit.timeit("f()", setup="from __main__ import f, fruits"), f()
在我的机器上 Python 2.7:
f1 8.09958791733 [['watermelon', 'pear', 'apple', 'banana'], ['pear', 'pineapple']]
f2 15.5085151196 [['pear', 'pineapple'], ['apple', 'pear', 'banana', 'watermelon']]
f3 11.9473619461 [['pear', 'pineapple'], ['apple', 'pear', 'banana', 'watermelon']]
f4 5.87942910194 [['watermelon', 'pear', 'apple', 'banana'], ['pear', 'pineapple']]
filter(lambda f: not any(set(f) < set(g) for g in fruits), fruits)
假设我有一个如下所示的列表列表(实际列表要长得多):
fruits = [['apple', 'pear'],
['apple', 'pear', 'banana'],
['banana', 'pear'],
['pear', 'pineapple'],
['apple', 'pear', 'banana', 'watermelon']]
在这种情况下,列表 ['banana', 'pear']
、['apple', 'pear']
和 ['apple', 'pear', 'banana']
中的所有项目都包含在列表 ['apple', 'pear', 'banana', 'watermelon']
中(项目的顺序无关紧要) ),所以我想删除 ['banana', 'pear']
、['apple', 'pear']
和 ['apple', 'pear', 'banana']
,因为它们是 ['apple', 'pear', 'banana', 'watermelon']
的子集。
我目前的解决方案如下所示。我首先使用 ifilter
和 imap
为每个列表可能具有的超集创建生成器。然后对于那些确实有超集的情况,我使用 compress
和 imap
来删除它们。
from itertools import imap, ifilter, compress
supersets = imap(lambda a: list(ifilter(lambda x: len(a) < len(x) and set(a).issubset(x), fruits)), fruits)
new_list = list(compress(fruits, imap(lambda x: 0 if x else 1, supersets)))
new_list
#[['pear', 'pineapple'], ['apple', 'pear', 'banana', 'watermelon']]
我想知道是否有更有效的方法来做到这一点?
我不知道它是否更快但这更容易阅读(无论如何对我来说):
sets={frozenset(e) for e in fruits}
us=set()
while sets:
e=sets.pop()
if any(e.issubset(s) for s in sets) or any(e.issubset(s) for s in us):
continue
else:
us.add(e)
更新
速度很快。更快的方法是使用 for
循环。检查时间:
fruits = [['apple', 'pear'],
['apple', 'pear', 'banana'],
['banana', 'pear'],
['pear', 'pineapple'],
['apple', 'pear', 'banana', 'watermelon']]
from itertools import imap, ifilter, compress
def f1():
sets={frozenset(e) for e in fruits}
us=[]
while sets:
e=sets.pop()
if any(e.issubset(s) for s in sets) or any(e.issubset(s) for s in us):
continue
else:
us.append(list(e))
return us
def f2():
supersets = imap(lambda a: list(ifilter(lambda x: len(a) < len(x) and set(a).issubset(x), fruits)), fruits)
new_list = list(compress(fruits, imap(lambda x: 0 if x else 1, supersets)))
return new_list
def f3():
return filter(lambda f: not any(set(f) < set(g) for g in fruits), fruits)
def f4():
sets={frozenset(e) for e in fruits}
us=[]
for e in sets:
if any(e < s for s in sets):
continue
else:
us.append(list(e))
return us
if __name__=='__main__':
import timeit
for f in (f1, f2, f3, f4):
print f.__name__, timeit.timeit("f()", setup="from __main__ import f, fruits"), f()
在我的机器上 Python 2.7:
f1 8.09958791733 [['watermelon', 'pear', 'apple', 'banana'], ['pear', 'pineapple']]
f2 15.5085151196 [['pear', 'pineapple'], ['apple', 'pear', 'banana', 'watermelon']]
f3 11.9473619461 [['pear', 'pineapple'], ['apple', 'pear', 'banana', 'watermelon']]
f4 5.87942910194 [['watermelon', 'pear', 'apple', 'banana'], ['pear', 'pineapple']]
filter(lambda f: not any(set(f) < set(g) for g in fruits), fruits)