Упрощение кода для понимания словаря

В каталоге изображений изображения называются как - 1_foo.png , 2_foo.png , 14_foo.png и т. Д.

Изображения являются OCR'ами, а извлечение текста хранится в тексте с помощью кода ниже -

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 ?

Всего 3 ответа


Да. Вот один из способов, но я бы не стал его рекомендовать:

{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)}

Это может быть настолько чисто, насколько я могу это сделать, и это все еще плохо. Лучше использовать нормальную петлю, особенно чистую, как у Денниса.

Незначительные изменения (если я сделаю оскорбление один раз, я мог бы сделать это дважды):

{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 теперь опубликовал хороший, используя понимание dict. Я бы порекомендовал это и над моим. Мои на самом деле просто грязные результаты, когда я говорю: «Кто-то сказал, что это невозможно сделать? Вызов принят!» ,


Нет. Каждая итерация в понимании dict присваивает значение ключу; он не может обновить существующий список значений. Dict понимания не всегда лучше - код, который вы написали, кажется достаточно хорошим. Хотя, возможно, вы могли бы написать

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)

В этом случае itertools.groupby может быть полезен; Вы можете сгруппировать имена файлов по числовой части. Но заставить его работать не легко, потому что группы должны быть смежными в последовательности.

Это означает, что прежде чем мы сможем использовать groupby , нам нужно отсортировать, используя функцию ключа, которая извлекает числовую часть. Это та же самая ключевая функция, которую мы хотим сгруппировать, поэтому имеет смысл написать ключевую функцию отдельно.

from itertools import groupby

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

images = [Ƈ_foo.png', ƈ_foo.png', Ɖ_bar.png', Ƈ_baz.png']

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

# {Ƈ': [Ƈ_foo.png', Ƈ_baz.png'],
#  ƈ': [ƈ_foo.png'],
#  Ɖ': [Ɖ_bar.png']}

Замените list(v) list(map(pytesseract.image_to_string, v)) для вашего list(map(pytesseract.image_to_string, v)) использования.