Список списков python для диктовки, когда ключ появляется много раз

Я знаю, что нужно написать что-то простое и медленное с циклом, но мне нужно, чтобы это работало очень быстро в больших масштабах.

вход:

lst = [[1, 1, 2], ["txt1", "txt2", "txt3"]]

желаемый результат:

d = {1 : ["txt1", "txt2"], 2 : "txt3"]

В python есть что-то встроенное, что делает ключ расширения dict() вместо его замены?

dict(list(zip(lst[0], lst[1])))

нет никакого способа позволить этому «работать очень быстро в больших масштабах». - вам нужно перебрать все элементы, вам нужно создать внутренние списки, вам нужно либо проверить/добавить, либо использовать что-то вроде defaultdict.

Patrick Artner 17.03.2022 18:25

Вы должен хотите ['txt3'], а не 'txt3'. Подробности смотрите в моем ответе.

timgeb 17.03.2022 18:34
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
48
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Один из вариантов — использовать dict.setdefault:

out = {}
for k, v in zip(*lst):
    out.setdefault(k, []).append(v)

Выход:

{1: ['txt1', 'txt2'], 2: ['txt3']}

Если вам нужен сам элемент для одноэлементных списков, одним из способов является добавление условия, которое проверяет его при создании выходного словаря:

out = {}
for k,v in zip(*lst):
    if k in out: 
        if isinstance(out[k], list):
            out[k].append(v)
        else:
            out[k] = [out[k], v]
    else:
        out[k] = v

или если lst[0] отсортировано (как в вашем образце), вы можете использовать itertools.groupby:

from itertools import groupby
out = {}
pos = 0
for k, v in groupby(lst[0]):
    length = len([*v])
    if length > 1:
        out[k] = lst[1][pos:pos+length]
    else:
        out[k] = lst[1][pos]
    pos += length

Выход:

{1: ['txt1', 'txt2'], 2: 'txt3'}

Но, как отмечает @timgeb, это, вероятно, не то, что вам нужно, потому что впоследствии вам придется проверять тип данных каждый раз, когда вы обращаетесь к этому словарю (если значение является списком или нет), что является ненужной проблемой, которую вы могли бы избежать, имеющие все значения в виде списков.

Обратите внимание, что OP не нужны списки с одним элементом. Что ошибочно, конечно.

timgeb 17.03.2022 18:35

@timgeb Спасибо, что указали на это; и я согласен с вашим комментарием

enke 17.03.2022 19:02

Вы можете использовать defaultdict, чтобы сгруппировать строки по соответствующему ключу, а затем сделать второй проход по списку, чтобы извлечь строки из одноэлементных списков. Независимо от того, что вы делаете, вам нужно получить доступ к каждому элементу в обоих списках хотя бы один раз, поэтому необходима структура итерации некоторый (и даже если вы не используете итерацию явно, все, что вы используете, почти наверняка будет использовать итерацию под капотом ):

from collections import defaultdict

lst = [[1, 1, 2], ["txt1", "txt2", "txt3"]]

result = defaultdict(list)
for key, value in zip(lst[0], lst[1]):
    result[key].append(value)

for key in result:
    if len(result[key]) == 1:
        result[key] = result[key][0]

print(dict(result)) # Prints {1: ['txt1', 'txt2'], 2: 'txt3'}

Обратите внимание, что OP не нужны списки с одним элементом. Что ошибочно, конечно.

timgeb 17.03.2022 18:35

Отредактировано, спасибо, что указали на это.

BrokenBenchmark 17.03.2022 18:44

Если вы имеете дело с большими наборами данных, может быть полезно добавить решение pandas.

>>> import pandas as pd
>>> lst = [[1, 1, 2], ["txt1", "txt2", "txt3"]]
>>> s = pd.Series(lst[1], index=lst[0])
>>> s 
1    txt1
1    txt2
2    txt3
>>> s.groupby(level=0).apply(list).to_dict()
{1: ['txt1', 'txt2'], 2: ['txt3']}

Обратите внимание, что это также создает списки для отдельных элементов (например, ['txt3']), которые я настоятельно рекомендую. Наличие как списков, так и строк в качестве возможных значений будем приводит к ошибкам, поскольку оба эти типа являются итерируемыми. Вам нужно будет не забывать проверять тип каждый раз, когда вы обрабатываете значение dict.

Другие вопросы по теме