考虑每个序列都是一个集合。现在我们只需丢弃所有子集。
给定:
import itertools as it
expected = {("A", "B", "C", ""), ("A", "", "", "D")}
data = [
("A", "B", "", ""),
("A", "B", "C", ""),
("", "", "", "D"),
("A", "", "", "D"),
("", "B", "", "")
]
代码
一种将集合转换并比较的迭代解决方案。
def discard_subsets(pool: list) -> set:
"""Return a set without subsets."""
discarded = set()
for n, k in it.product(pool, repeat=2):
if set(k) < set(n)):
discarded.add(k)
return set(pool) - discarded
一种类似的单行解决方案。
set(data) - {k for n, k in it.product(data, repeat=2) if set(k) < set(n)}
演示
discard_subsets(data)
# {('A', '', '', 'D'), ('A', 'B', 'C', '')}
细节
后面的函数是有注释的,以帮助解释每个部分:
- 将所有元素相互比较(或使用嵌套循环)。
- 如果一个元素是一个真子集(见下文),则舍弃它。
- 从池中删除被舍弃的元素。
为什么要使用集合?
池中的每个元素都可以是一个集合,因为相关的子元素是唯一的,即 "A","B","C","D",""
。
集合具有成员属性。因此,例如,
("A", "B", "", "")
具有 ("A", "B", "C", "")
中的所有值
也可以表示为
集合 {"A", "B", "", ""}
是集合 {"A", "B", "C", ""}
的子集
现在只需要比较所有元素并拒绝所有 真子集。
a, a_, ac = {"a"}, {"a"}, {"a", "c"}
assert a.issubset(a_)
assert a <= a_
assert a <= ac
assert not a < a_
assert a < ac
复杂度
由于我们基本上有嵌套循环,最好的情况下我们得到O(n^2)的复杂度。这可能不是最有效的方法,但希望足够清晰易懂。
测试
f = discard_subsets
assert {("A", "B", "C", "")} == f([("A", "B", "", ""), ("A", "B", "C", "")])
assert {("A", "B", "C", "")} == f([("A", "B", "C", ""), ("A", "B", "", "")])
assert {("A", "B", "C", ""), ("", "", "", "D")} == f([("A", "B", "", ""), ("A", "B", "C", ""), ("", "", "", "D")])
assert {("A", "B", "C", ""), ("", "", "", "D")} == f([("", "", "", "D"), ("A", "B", "", ""), ("A", "B", "C", "")])
assert {("A", "B", "C", ""), ("", "", "", "D")} == f([("A", "B", "C", ""), ("", "", "", "D"), ("A", "B", "", "")])
assert {("A", "B", "C", ""), ("", "", "", "D")} == f([("A", "B", "C", ""), ("A", "B", "", ""), ("", "", "", "D")])
assert {("A","","C"), ("","B","C"), ("A","B","")} == f([("A","","C"),("","B","C"),("","","C"),("A","",""),("","",""),("A","B",""),("","B","")])
assert set(expected) == f(data)