我正在尝试删除超集(如果我的集合中有任何集合)并且只返回集合中的子集。我写了下面的代码,但由于处理大型数据集需要很长时间才能执行,有人可能会为此建议其他选项。
例如,如果我有一组这样的冻结
skt = {{D},{E,D,M},{E,M}}
我需要像
这样的输出skt = {{D},{E,M}}
我的代码是,
for item in skt.copy():
for other_item in skt.difference([item]):
if item >= other_item:
skt.remove(item)
break
提前致谢。
答案 0 :(得分:3)
至少可以进行一些小的优化:不要复制一套,而是创建一个新的:
newset = set()
for x in skt:
if not any(y < x for y in skt):
newset.add(x)
或者在一行中:
newset = set(x for x in skt if not any(y < x for y in skt))
<强>更新强>
您可以为每个元素预先计算包含该元素的集合集,然后仅针对包含至少一个元素的集合检查每个集合:
setsForElement = defaultdict(set);
for s in skt:
for element in s:
setsForElement[element].add(s);
newset = set(s for s in skt if not any (setForElement < s for element in s for setForElement in setsForElement[element]))
# last line is equal to:
newset = set();
for s in skt:
good = True;
for element in s:
if any(setForElement < s for setForElement in setsForElement[element]):
good = False;
break;
if good:
newset.add(s);
根据您的数据集,它可能会节省您一些时间。当然,在最坏的情况下(例如,如果您的数据集是某个集合的power set),复杂性将再次为O(N ^ 2)集合比较。或者考虑一下,它可能比直接算法更糟糕,因为你可能多次检查同一组。
答案 1 :(得分:1)
理解
对于列表L的集合,返回L
中没有超集的集合skt = {{D},{E,D,M},{E,M}}
out = {{D}, {E,M}}
和
skt = {{D}, {E,G}, {E,H}, {D,E,F}, {E,F,G}}
out = {{D}, {E,G}, {E,H}, {D,E,F}}
如果那是正确的(在我的脑海里,我可能是错的)最坏的情况总是迫使你检查所有对。您可以进行改进,例如不迭代已经删除的元素。或者只检查每一对,并在两个方向上进行,并相应地更新。 itertools.product可能很有用,但同样,它不会更新,所以当你删除一个元素时,我不确定什么是有效的。
更优化的代码可能是:
skt = {frozenset({1}), frozenset({1,2,3}), frozenset({2,3}), frozenset({4}),
frozenset({5,7}), frozenset({5,8}), frozenset({5,6,7}),
frozenset({6,7,8})}
newset = set()
def check(elem):
to_delete = []
ret = True
for y in skt:
if elem > y:
to_delete.append(elem)
ret = False
break
if y > elem:
to_delete.append(y)
for d in to_delete:
skt.remove(d)
return ret
while skt:
checking = skt.pop()
if check(checking):
newset.add(checking)
答案 2 :(得分:1)
这种方法与您的方法基本相同,但它按升序基数的顺序运行。优势可能很大,具体取决于您的数据(如果有一些小集可以在早期迭代中淘汰其他很多)。
from collections import defaultdict
def foo(skt):
# Index the sets by cardinality
index = defaultdict(lambda: set())
for s in skt:
index[len(s)].add(s)
# For each cardinality i, starting with the lowest
for i in range(max(index.keys()) + 1):
# For each cardinality j > i (because supersets must be larger)
for j in range(i + 1, max(index.keys()) + 1):
# Remove j-sized supersets
for y in [y for y in index[j] if any(y >= x for x in index[i])]:
index[j].remove(y)
# Flatten the index
return set(x for xs in index.values() for x in xs)