在您的实现中,您正在重新发明itertools.permutations(),它返回具有给定长度的元素的排列。您可以比较使用嵌套的for 循环(来自您的代码示例) 和permutations() 生成的列表:
from itertools import permutations
strings = ["a", "aa", "b"]
res = []
for i, subA in enumerate(strings):
for j, subB in enumerate(strings):
if i != j:
res.append((subA, subB))
print("Nested loop:", res)
res = list(permutations(strings, 2))
print("permutations():", res)
您需要检查每个元素是否是另一个元素的子字符串,因此您可以迭代从permutations() 返回的对,并测试第一个元素是否包含第二个(反之亦然)。让我们用简单的列表理解来做吧:
from itertools import permutations
strings = ["a", "aa", "b"]
res = [a in b for a, b in permutations(strings, 2)]
# will return [True, False, False, False, False, False]
在 python 中,True 是 1,False 是 0 (docs)。因此,要计算有多少字符串是子字符串,我们可以将 生成器表达式 传递给 sum()。
from itertools import permutations
strings = ["a", "aa", "b"]
num = sum(a in b for a, b in permutations(strings, 2))
# will return 1
您也可以使用itertools.starmap() 调用operator.contains() (与a in b 相同) 每对都由permutations() 返回。
from operator import contains
from itertools import permutations, starmap
strings = ["a", "aa", "b"]
num = sum(starmap(contains, permutations(strings, 2)))
这是您的代码的一些改进版本:
from operator import contains
from itertools import permutations, starmap
count = input("How many strings? ")
if count.isdecimal() and (count := int(count)):
strings = []
while count:
item = input(f"String ({count} left): ")
if item: # skip empty strings
strings.append(item)
count -= 1
num = sum(starmap(contains, permutations(strings, 2)))
print("There", "are" if num > 1 else "is", num or "no",
"substring" + "s" * (num != 1))
else:
print(f'"{count}" is not a valid positive number')
P.S.关于性能的一些说明。
由于sum() 处理可迭代的方法,您可以使用生成器表达式对代码进行一些补丁以更快地工作。
sum([1 for a, b in permutations(strings, 2) if a in b])
会略快于
sum(a in b for a, b in permutations(strings, 2))
为什么?看看接下来的问题:
-
Why is summing list comprehension faster than generator expression?;
-
Why is any (True for ... if cond) much faster than any (cond for ...)?。