python преобразовать список в словарь [дубликат]
этот вопрос уже есть ответ здесь:
- преобразование списка в словарь на Python 13 ответов
l = ["a", "b", "c", "d", "e"]
Я хочу преобразовать этот список в словарь, например:
d = {"a": "b", "c": "d", "e": ""}
таким образом, в основном, эвены будут ключами, тогда как шансы будут значениями. Я знаю, что я могу сделать это в "не-подходящие для Python" способ такой как цикл for с утверждениями if, но я считаю, что для этого должен быть более "питонический" способ. Так что, я ценю любую помощь:)
4 ответа:
через обычный рецепт окунь, вы могли бы сделать:
Python 2:
d = dict(itertools.izip_longest(*[iter(l)] * 2, fillvalue=""))
Python 3:
d = dict(itertools.zip_longest(*[iter(l)] * 2, fillvalue=""))
если вы все еще думаете, что! Вы не будете одиноки, на самом деле это не так сложно, позвольте мне объяснить.
как превратить список в словарь, используя только встроенные функции
мы хотим превратить следующий список в словарь, используя нечетные записи (считая от 1) в качестве ключей, сопоставленных с их последовательными четными записями.
l = ["a", "b", "c", "d", "e"]
dict ()
для создания словаря мы можем использовать встроенный который в основном использует ряд или короткий фрагмент нотация, но это то, что долго кусочек нотация выглядит как и то, что мы можем сделать с шаг:
>>> l[::2] ['a', 'c', 'e'] >>> l[1::2] ['b', 'd'] >>> zip(['a', 'c', 'e'], ['b', 'd']) [('a', 'b'), ('c', 'd')] >>> dict(zip(l[::2], l[1::2])) {'a': 'b', 'c': 'd'}
несмотря на то, что это самый простой способ понять механику, есть недостаток, потому что срезы каждый раз являются новыми объектами списка, как видно из этого примера клонирования:
>>> a = [1, 2, 3] >>> b = a >>> b [1, 2, 3] >>> b is a True >>> b = a[:] >>> b [1, 2, 3] >>> b is a False
несмотря на то, что b выглядит как a, теперь они являются двумя отдельными объектами, и именно поэтому мы предпочитаем использовать рецепт окунь вместо.
групер рецепт
хотя grouper объясняется как часть модуля itertools, он отлично работает и с основными функциями.
какое-то серьезное вуду, верно? = ) Но на самом деле не более чем немного синтаксического сахара для специй, рецепт групера выполняется следующим выражением.
*[iter(l)]*2
который более или менее переводится в два аргумента одного и того же итератора, завернутого в список, если это имеет смысл. Давайте разбить его, чтобы помочь пролить немного света.
zip для самых коротких
>>> l*2 ['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e'] >>> [l]*2 [['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']] >>> [iter(l)]*2 [<listiterator object at 0x100486450>, <listiterator object at 0x100486450>] >>> zip([iter(l)]*2) [(<listiterator object at 0x1004865d0>,),(<listiterator object at 0x1004865d0>,)] >>> zip(*[iter(l)]*2) [('a', 'b'), ('c', 'd')] >>> dict(zip(*[iter(l)]*2)) {'a': 'b', 'c': 'd'}
как вы можете видеть, адреса для двух итераторов остаются одинаковыми, поэтому мы работаем с одним и тем же итератором, который zip сначала получает ключ, а затем значение и ключ и значение каждый раз, когда шагает один и тот же итератор, чтобы выполнить то, что мы сделали с срезами гораздо более продуктивно.
вы бы сделали очень много то же самое со следующим, который несет меньший что? фактор возможно.
>>> it = iter(l) >>> dict(zip(it, it)) {'a': 'b', 'c': 'd'}
а как же пустой ключ
e
если вы заметили, что он отсутствовал во всех примерах, потому чтоzip
выбирает кратчайший из двух аргументов, так что же нам делать.Ну, одним из решений может быть добавление пустого значения в списки нечетной длины, вы можете использовать
append
иif
заявление, которое будет делать трюк, хотя и немного скучно, не так ли?>>> if len(l) % 2: ... l.append("") >>> l ['a', 'b', 'c', 'd', 'e', ''] >>> dict(zip(*[iter(l)]*2)) {'a': 'b', 'c': 'd', 'e': ''}
теперь, прежде чем вы пожимаете плечами, чтобы уйти типа
from itertools import izip_longest
вы можете быть удивлены, узнав, что это не требуется, мы можем выполнить то же самое, даже лучше ИМХО, с помощью встроенных функций в одиночку.карта для длинной
я предпочитаю использовать функция map () вместо izip_longest () который не только использует более короткий синтаксис не требует импорта, но он может назначить фактический
None
пустое значение при необходимости, автоматически.>>> l = ["a", "b", "c", "d", "e"] >>> l ['a', 'b', 'c', 'd', 'e'] >>> dict(map(None, *[iter(l)]*2)) {'a': 'b', 'c': 'd', 'e': None}
сравнение производительности двух методы, как указывает KursedMetal, ясно, что модуль itertools намного превосходит функцию map на больших объемах, как показывает бенчмарк против 10 миллионов записей.
$ time python -c 'dict(map(None, *[iter(range(10000000))]*2))' real 0m3.755s user 0m2.815s sys 0m0.869s $ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(10000000))]*2, fillvalue=None))' real 0m2.102s user 0m1.451s sys 0m0.539s
однако стоимость импорта модуля имеет свои последствия для небольших наборов данных с картой, возвращающейся намного быстрее, до примерно 100 тысяч записей, когда они начинают прибывать голова к голове.
$ time python -c 'dict(map(None, *[iter(range(100))]*2))' real 0m0.046s user 0m0.029s sys 0m0.015s $ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100))]*2, fillvalue=None))' real 0m0.067s user 0m0.042s sys 0m0.021s $ time python -c 'dict(map(None, *[iter(range(100000))]*2))' real 0m0.074s user 0m0.050s sys 0m0.022s $ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100000))]*2, fillvalue=None))' real 0m0.075s user 0m0.047s sys 0m0.024s
ничего не вижу! =)
nJoy!