将代码简化为字典理解

Simplifying the code to a dictionary comprehension

在目录 images 中,图像命名为 - 1_foo.png , 2_foo.png, 14_foo.png,等等

图像经过 OCR 处理,文本提取通过以下代码存储在 dict 中 -

data_dict = {}

for i in os.listdir(images):
    if str(i[1]) != '_':
        k = str(i[:2])  # Get first two characters of image name and use as 'key'
    else:
        k = str(i[:1])  # Get first character of image name and use 'key'
    # Intiates a list for each key and allows storing multiple entries
    data_dict.setdefault(k, [])
    data_dict[k].append(pytesseract.image_to_string(i))

代码按预期执行。
图片的名称中可以有不同的数字,范围从 1 到 99。
这可以减少到 dictionary comprehension 吗?

没有。字典理解中的每次迭代都会为键分配一个值;它无法更新现有值列表。字典理解并不总是更好——您编写的代码似乎已经足够好了。虽然也许你可以写

data_dict = {}

for i in os.listdir(images):
    k = i.partition("_")[0]
    image_string = pytesseract.image_to_string(i)
    data_dict.setdefault(k, []).append(image_string)

是的。这是一种方法,但我不推荐它:

{k: d.setdefault(k, []).append(pytesseract.image_to_string(i)) or d[k]
 for d in [{}]
 for k, i in ((i.split('_')[0], i) for i in names)}

这可能是我能做到的最干净的了,但它仍然很糟糕。最好使用普通循环,尤其是像 Dennis 那样干净的循环。

略有不同(如果我滥用一次,我不妨再做两次):

{k: d.setdefault(k, []).append(pytesseract_image_to_string(i)) or d[k]
 for d in [{}]
 for i in names
 for k in i.split('_')[:1]}

编辑:kaya3 现在发布了一个 good 一个使用字典理解的。我也会推荐我的。我真的只是我像 "Someone said it can't be done? Challenge accepted!".

这样的肮脏结果

在这种情况下itertools.groupby会很有用;您可以按数字部分对文件名进行分组。但是让它工作并不容易,因为这些组在序列中必须是连续的。

这意味着在我们可以使用 groupby 之前,我们需要使用提取数字部分的键函数进行排序。这与我们要分组的键函数相同,因此单独编写键函数是有意义的。

from itertools import groupby

def image_key(image):
    return str(image).partition('_')[0]

images = ['1_foo.png', '2_foo.png', '3_bar.png', '1_baz.png']

result = {
    k: list(v)
    for k, v in groupby(sorted(images, key=image_key), key=image_key)
}

# {'1': ['1_foo.png', '1_baz.png'],
#  '2': ['2_foo.png'],
#  '3': ['3_bar.png']}

list(v) 替换为 list(map(pytesseract.image_to_string, v)) 用于您的用例。