给定一个包含多个迭代的列表,我想测试是否所有项都是disjoint。
如果他们没有共同的元素,则认为两组不相交
示例:
iterables = ["AB", "CDE", "AF"]
all_disjoint(iterables)
# False
iterables = ["AB", "CDE", "FG"]
all_disjoint(iterables)
# True
Python集合有一个isdisjoint
方法可行,但它设计用于一次测试两个元素。一种方法是将此方法应用于每个成对的元素组:
import itertools as it
def pairwise_(iterable):
"""s -> (s0,s1), (s1,s2), (s2,s3), ..., (sn,s0)"""
# Modified: the last element wraps back to the first element.
a, b = it.tee(iterable, 2)
first = next(b, None)
b = it.chain(b, [first])
return zip(a, b)
def all_disjoint(x):
return all((set(p0).isdisjoint(set(p1))) for p0, p1 in pairwise_(x))
我在这里修改了pairwise
itertools recipe以便最后一次附加第一个元素。但这并不完全正确,因为它只测试相邻项目而不是每个项目对照列表中的所有其他项目。我想用更少的代码更优雅地测试所有元素。有更简单的方法吗?
答案 0 :(得分:6)
IIUC,您可以获取字符串列表,组合它们,然后检查组合长度是否等于该字符串的等效设置长度。
您可以使用''.join
加入字符串并定义您的功能:
def all_disjoint(iterables):
total = ''.join(iterables)
return len(total) == len(set(total))
现在,测试:
all_disjoint(['AB', 'CDE', 'AF'])
# False
all_disjoint(['AB', 'CDE', 'FG'])
# True
答案 1 :(得分:1)
首先,<div *ngIf="isAndroidTablet()">...</div>
会导致设置set(list('AB'))
。
其次,通过枚举{'A', 'B'}
然后使用s
,只查看上对角线,避免需要将值与自身或另一对进行比较。例如,如果for s2 in s[n+1:]
,那么[(s1,s2)对于n,s1在s [n + 1:]]中对s2的枚举将导致:s = ['A', 'B', 'C']
。如果要从[('A', 'B'), ('A', 'C'), ('B', 'C')]
导入list(combinations(s, 2))
,则相当于combinations
的结果。
鉴于上述情况,我使用itertools
生成器来比较每个子集之间缺少任何交集。
由于any
构造,它会在第一次观察共同元素时短路,从而无需计算每对。
any
答案 2 :(得分:1)
鉴于您所说的想要测试每个项目与所有其他项目不相交,我认为这样做符合您的要求:
import itertools as it
def all_disjoint(x):
return all((set(p0).isdisjoint(set(p1))) for p0, p1 in it.combinations(x, 2))
iterables = ['AB', 'CDE', 'AF']
print(all_disjoint(iterables)) # -> False
iterables = ['AB', 'CDE', 'FG']
print(all_disjoint(iterables)) # -> True
# your code gives different answer on this one
# (because it doesn't check what you want)
iterables = ['AB', 'CDE', 'AH', 'FG']
print(all_disjoint(iterables)) # -> False
答案 3 :(得分:0)
我为有兴趣的人添加了这些答案。
方法1 :我意识到这可以通过multiset(Counter
)完成。
import itertools as it
import collections as ct
def all_disjoint(iterables):
return all(not v-1 for v in ct.Counter(it.chain.from_iterable(iterables)).values())
方法2 :从more_itertools
库中,more_itertools.unique_to_each
生成每个可迭代的所有唯一项。以下代码将结果的长度与原始iterables进行比较:
import more_itertools as mit
def all_disjoint(iterables):
return all(len(x) == len(y) for x, y in zip(iterables, mit.unique_to_each(*iterables)))