在列表推导中对itertools.groupby对象的if条件总是返回False
我得到了一个包含以下结构的文件列表:
[output-input]_[A-Z]_foo_bar_[0-n].pkl 的n 值不同
file_list = [
'output_A_foo_bar_0.pkl',
'output_A_foo_bar_1.pkl',
'output_A_foo_bar_2.pkl',
'output_A_foo_bar_3.pkl',
'output_B_foo_bar_0.pkl',
'output_B_foo_bar_1.pkl',
'output_B_foo_bar_2.pkl',
'output_B_foo_bar_3.pkl',
'output_G_foo_bar_1.pkl',
'output_H_foo_bar_0.pkl',
'output_H_foo_bar_1.pkl',
'input_A_foo_bar_0.pkl',
'input_H_foo_bar_0.pkl',
'input_H_foo_bar_1.pkl',
'input_H_foo_bar_2.pkl',
'input_H_foo_bar_3.pkl']
我想要的:
[['output_A_foo_bar_0.pkl',
'output_A_foo_bar_1.pkl',
'output_A_foo_bar_2.pkl',
'output_A_foo_bar_3.pkl',],
['output_B_foo_bar_0.pkl',
'output_B_foo_bar_1.pkl',
'output_B_foo_bar_2.pkl',
'output_B_foo_bar_3.pkl']
]
我尝试了这个:
file_list = [
'output_A_foo_bar_0.pkl',
'output_A_foo_bar_1.pkl',
'output_A_foo_bar_2.pkl',
'output_A_foo_bar_3.pkl',
'output_B_foo_bar_0.pkl',
'output_B_foo_bar_1.pkl',
'output_B_foo_bar_2.pkl',
'output_B_foo_bar_3.pkl',
'output_G_foo_bar_1.pkl',
'output_H_foo_bar_0.pkl',
'output_H_foo_bar_1.pkl',
'input_A_foo_bar_0.pkl',
'input_H_foo_bar_0.pkl',
'input_H_foo_bar_1.pkl',
'input_H_foo_bar_2.pkl',
'input_H_foo_bar_3.pkl']
res = [list(i)
for j, i in itertools.groupby(file_list, lambda a: a.rsplit('_', maxsplit=1)[0])
if ('output' in j) and (sum(1 for x in i) == 4)
]
print(res)
结果: [[],[]]
还有这个:
file_list = [
'output_A_foo_bar_0.pkl',
'output_A_foo_bar_1.pkl',
'output_A_foo_bar_2.pkl',
'output_A_foo_bar_3.pkl',
'output_B_foo_bar_0.pkl',
'output_B_foo_bar_1.pkl',
'output_B_foo_bar_2.pkl',
'output_B_foo_bar_3.pkl',
'output_G_foo_bar_1.pkl',
'output_H_foo_bar_0.pkl',
'output_H_foo_bar_1.pkl',
'input_A_foo_bar_0.pkl',
'input_H_foo_bar_0.pkl',
'input_H_foo_bar_1.pkl',
'input_H_foo_bar_2.pkl',
'input_H_foo_bar_3.pkl']
res = [list(i)
for j, i in itertools.groupby(file_list, lambda a: a.rsplit('_', maxsplit=1)[0])
if ('output' in j) and (len(list(i)) == 4)
]
print(res)
结果: [[],[]]
但在这两种情况中,if 语句的第二部分(在itertools对象 i 上)总是 False。我肯定遗漏了什么,但我还想不出到底是什么。
解决方案
你当前代码中对对象类型有一些混用,并且在两个版本中都存在一个问题:你对由 groupby 返回的组(你的 j)的使用。它不是一个列表,而是一个迭代器,因此如果你尝试在第二次使用它时(比如在 list(j) 之类的地方)它就会被耗尽。
我们不能用它第一次来得到长度,再用第二次来创建一个列表。所以,我们要么在后续按长度过滤,要么在第一次遍历分组时就使用 := 的赋值来创建一个列表(也就是在 if 子句中——它会先执行,然后列表再被加入输出中)。
我也建议不要把太多内容放进那个大型的列表推导式,在尝试分组之前就过滤掉有效的文件名(如果其中一个文件的格式无效,你的代码就会失败)。
所以,你可以这样做:
from itertools import groupby
import re
file_list = [
'output_A_foo_bar_0.pkl',
'output_A_foo_bar_1.pkl',
'output_A_foo_bar_2.pkl',
'output_A_foo_bar_3.pkl',
'output_B_foo_bar_0.pkl',
'output_B_foo_bar_1.pkl',
'output_B_foo_bar_2.pkl',
'output_B_foo_bar_3.pkl',
'output_G_foo_bar_1.pkl',
'output_H_foo_bar_0.pkl',
'output_H_foo_bar_1.pkl',
'input_A_foo_bar_0.pkl',
'input_H_foo_bar_0.pkl',
'input_H_foo_bar_1.pkl',
'input_H_foo_bar_2.pkl',
'input_H_foo_bar_3.pkl']
# we filter the valid filenames *before* trying to group them,
# so we can be sure that a valid key will exist
valid_pattern = re.compile(r"output_[A-Z]_")
# we filter with a generator expression, no intermediate list will be created
valid_names = (f for f in file_list if valid_pattern.match(f))
out = [lst for key, grp in groupby(valid_names, key=lambda x: x.split('_')[1])
if len(lst:=list(grp))==4]
print(out)
输出:
[['output_A_foo_bar_0.pkl',
'output_A_foo_bar_1.pkl',
'output_A_foo_bar_2.pkl',
'output_A_foo_bar_3.pkl'],
['output_B_foo_bar_0.pkl',
'output_B_foo_bar_1.pkl',
'output_B_foo_bar_2.pkl',
'output_B_foo_bar_3.pkl']]
在没有 := 赋值的较旧版本的Python中,你可以,例如这样做:
res = (list(grp) for key, grp in groupby(valid_names, key=lambda x: x.split('_')[1]))
out = [l for l in res if len(l)==4]
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。