我有一个包含subjectid_num_ [dog / cat] _ [option]的txt文件。
ID1_0123_CAT_ANIMAL_3
ID1_0123_CAT_ANIMAL_GOOD_3
ID1_0123_ABC_3
ID2_1234_CAT_ANIMAL_3
ID2_1234_CAT_ANIMAL_GOOD_3
ID2_1234_DOG_ANIMAL_2
ID2_1234_DOG_ANIMAL_GOOD_0
ID2_1234_ABCD_3
ID3_4321_DOG_ANIMAL_1
ID3_4321_DOG_ANIMAL_GOOD_4
ID3_4321_DOG_3
我想过滤文件以获得满足条件的输出。例如,下面的代码将在文件名中输出CAT
和GOOD
,并且名称中不包含DOG
和GOOD
。该名称由相同的subject_id
和相同的数字num
决定。但是,代码不显示我的预期输出。我该如何解决?
这是我的代码
with open("./cat_dog.txt", 'r') as f:
files_list = [line.rstrip('\n') for line in f]
file_filter = []
for i, cat in enumerate(files_list):
if 'GOOD' in cat and 'CAT' in cat:
subject_id = cat.split('_')[0]
num_id = cat.split('_')[1]
subject_num = subject_id + '_' + num_id
for j, dog in enumerate(files_list):
if subject_num in dog and 'GOOD' in dog:
if 'GOOD' in dog and 'DOG' in dog:
continue;
else:
file_filter.append(cat)
目前的输出是
ID1_0123_CAT_ANIMAL_GOOD_3
ID2_1234_CAT_ANIMAL_GOOD_3
虽然预期是
ID1_0123_CAT_ANIMAL_GOOD_3
你的代码错了。考虑一下在内循环中检查行ID2_1234_CAT_ANIMAL_GOOD_3
时会发生什么:
subject_id = cat.split('_')[0] #ID2
num_id = cat.split('_')[1] # 1234
subject_num = subject_id + '_' + num_id #ID2_1234
for j, dog in enumerate(files_list):
# when dog is the line ID2_1234_CAT_ANIMAL_GOOD_3
if subject_num in dog and 'GOOD' in dog: # this is true
if 'GOOD' in dog and 'DOG' in dog: # this is false
continue;
else:
file_filter.append(cat) # then it outputs it
问题是其中包含GOOD
和CAT
的每一行都将在内循环中“匹配”。
恕我直言,我会使用itertools.groupby
。有点像:
from itertools import groupby
def key(line):
return line.split('_')[:2]
for key, lines in groupby(sorted(files_list, key=key), key=key):
good_lines = [line for line in lines if 'GOOD' in line]
if len(good_lines) == 1 and 'CAT' in good_lines[0]:
file_filter.append(good_lines[0])
这也应该是更有效的O(nlog n)vs O(n ^ 2),尽管它需要RAM中文件的所有内容。
如果你有除CAT
和DOG
以外的其他“类”并且你想输出所有GOOD CAT
线,除非subject_id
也是GOOD
DOG
你可以用这种方式修改上面的代码:
is_good_cat = any('CAT' in line for line in good_lines)
is_good_dog = any('DOG' in line for line in good_lines)
if is_good_cat and not is_good_dog:
file_filter.extend(line for line in good_lines if 'CAT' in good_lines)
(你需要使用.extend
和循环,因为我们不再知道哪一行是要写的,所以你必须过滤它们。