python преобразовать список в словарь [дубликат]


этот вопрос уже есть ответ здесь:

l = ["a", "b", "c", "d", "e"]

Я хочу преобразовать этот список в словарь, например:

d = {"a": "b", "c": "d", "e": ""}

таким образом, в основном, эвены будут ключами, тогда как шансы будут значениями. Я знаю, что я могу сделать это в "не-подходящие для Python" способ такой как цикл for с утверждениями if, но я считаю, что для этого должен быть более "питонический" способ. Так что, я ценю любую помощь:)

4 64

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!

Я бы пошел на рекурсии:

l = ['a', 'b', 'c', 'd', 'e', ' ']
d = dict([(k, v) for k,v in zip (l[::2], l[1::2])])

Не уверен, поможет ли это вам или нет, но это работает для меня:

l = ["a", "b", "c", "d", "e"]
outRes = dict((l[i], l[i+1]) if i+1 < len(l) else (l[i], '') for i in xrange(len(l)))