我想找到所有 5 位数字的字符串,其中
- 前三位数字在我的第一个列表中,
- 第二个槽第四个数字在我的第二个列表中,
- 第三到第五个数字在我的最后一个列表中:
l0=["123","567","451"]
l1=["234","239","881"]
l2=["348","551","399"]
因此应该产生:
['12348', '12399']
因此我编写了一个函数
is_successor(a,b)
来测试 a 和 b 是否重叠:
def is_successor(a:str,b:str)->bool:
"""tests if strings a and b overlap"""
return a[1:]==b[:2]
然后我可以通过编写这个嵌套循环/检查结构来实现我的目标,即基本上追加到前面的字符串并产生所有有效的字符串:
pres=[]
for c in l2:
for b in l1:
if is_successor(b,c):
for a in l0:
if is_successor(a,b):
pres.append(a[0]+b[0]+c)
pres
- 我知道我可以将其编写为列表理解,但对于我的原始数据,我有更多嵌套列表,即使在列表理解中我也失去了可读性。
-
我从
l2
->l0
开始,因为在我的原始数据中,列表变得更长,索引越低,因此我可以通过这种方式尽早过滤掉更多案例。 -
通过
l0,l1,l2
的所有组合的单个循环并检查所有项目的连续性a,b,c
同时可以工作,但它测试的不必要的组合比我当前的构造更多。
问题 :
如何吸引这个嵌套循环和条件检查调用?有没有一种Python式的方法来捕获
for
->
is_successor()
的重复?
以下是使用生成器表达式和一些 itertools 函数(如
itertools.product
和
itertools.islice
)在 Python 中实现此目的的一种更 Pythonic 的方法:
import itertools
def is_successor(a: str, b: str) -> bool:
"""测试字符串 a 和 b 是否重叠"""
return a[1:] == b[:2]
def generate_strings(l0, l1, l2):
"""生成满足给定条件的所有 5 位数字字符串"""
for a, b, c in itertools.product(l0, l1, l2):
if is_successor(a, b) and is_successor(b, c):
yield a[0] + b[0] + c
l0 = ["123", "567", "451"]
l1 = ["234", "239", "881"]
l2 = ["348", "551", "399"]
result = list(generate_strings(l0, l1, l2))
print(result) # 输出:['12348', '12399']
下面是对代码的逐行解释:
-
import itertools
: 这会导入 Python 的itertools
模块,该模块提供了用于处理迭代器的各种函数,这些函数可以使代码更有效率和简洁。 -
def generate_strings(l0, l1, l2)
: 此函数使用生成器表达式生成满足给定条件的所有 5 位数字字符串。 -
for a, b, c in itertools.product(l0, l1, l2)
: 此行使用itertools.product()
函数从输入列表l0
、l1
和l2
生成所有可能的组合。这避免了显式嵌套循环。 -
if is_successor(a, b) and is_successor(b, c)
: 此条件检查a
、b
和c
的当前组合是否满足is_successor
函数定义的重叠条件。 -
yield a[0] + b[0] + c
: 如果组合满足条件,则此行会使用yield
关键字生成连接后的 5 位数字字符串。这会创建一个生成器函数,该函数在每次调用时生成一个字符串,从而使内存使用率保持较低,尤其是在处理大量数据时。
此代码避免使用显式嵌套循环,并且通过使用生成器表达式来创建字符串组合,从而使其更具 Python 风格,从而提高了可读性和效率。
标签:python,python-3.x From: 78810300