Упрощение кода для понимания словаря - PullRequest
0 голосов
/ 09 февраля 2020

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

Изображения распознаются с помощью оптического распознавания текста, а извлечение текста сохраняется в 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?

Ответы [ 3 ]

6 голосов
/ 09 февраля 2020

Нет. Каждая итерация в понимании 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)
3 голосов
/ 09 февраля 2020

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

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

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

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

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

2 голосов
/ 09 февраля 2020

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

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

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)) для вашего варианта использования.

...