2009-10-28 5 views
1

Я не могу найти элегантный способ начать с t и привести к s.Преобразование одного упорядоченного списка в python в словарь, pythonically

>>>t = ['a',2,'b',3,'c',4] 
#magic 
>>>print s 
{'a': 2, 'c': 4, 'b': 3} 

Solutions Я придумываю, что кажется менее элегантно:

s = dict() 
for i in xrange(0, len(t),2): s[t[i]]=t[i+1] 
# or something fancy with slices that I haven't figured out yet 

Это, очевидно, легко решается, но, опять-таки, похоже, что есть лучший путь. Здесь?

ответ

10

Я хотел бы использовать itertools, но, если вы считаете, что сложно (как вы намекнули в комментариях), то может быть:

def twobytwo(t): 
    it = iter(t) 
    for x in it: 
    yield x, next(it) 

d = dict(twobytwo(t)) 

или что то же самое, и обратно itertools снова,

def twobytwo(t): 
    a, b = itertools.tee(iter(t)) 
    next(b) 
    return itertools.izip(a, b) 

d = dict(twobytwo(t)) 

или, если вы настаиваете на том, рядный, в сезоне-соответствующий «трюк или лечения» настроение:

d = dict((x, next(it)) for it in (iter(t),) for x in it) 

меня, я считаю, это трюк, но некоторые могут найти это удовольствие. IOW, я нахожу такое страшное явление, но, видимо, в США в это время года есть , предположительно, чтобы быть ;-).

В основном проблема сводится к тому, «как мне вести список по 2 элемента за раз», потому что dict вполне счастлив взять последовательность из 2-х кортежей и превратить их в словарь. Все решения, которые я показываю здесь, обеспечивают только O(1) дополнительное пространство (за пределами пространства, очевидно O(N), это необходимо для ввода списка и выход dict, конечно).

Предлагаемый подход в docs (все должны быть знакомы с этой страницей, рецепты itertool) - это функция pairwise на этой странице, которая в основном является второй, которую я предложил здесь. Я думаю, что каждый каталог сайтов-пакетов должен содержать файл iterutils.py с этими рецептами (жаль, что такой файл уже не является частью stdlib!).

+2

+1 для «трюк» и ваше замечание о 'iterutils.py'. – Stephan202

7

Не совсем эффективно, но если вам не нужно это для очень больших списков:

dict(zip(t[::2], t[1::2])) 

Или ваша версия с использованием генератора:

dict(t[i:i+2] for i in xrange(0, len(t), 2)) 
1
dict(zip(t[::2], t[1::2])) 

, вероятно, не самый эффективный , работает в python 3; Вы, возможно, потребуется импортировать почтовый индекс, в Python 2.x

+1

Почтовый индекс сначала появился как встроенный в 2.0, согласно документам. – SingleNegationElimination

9

Та же идея, как Lukáš Lalinský's answer, другую идиому:

>>> dict(zip(*([iter(t)] * 2))) 
{'a': 2, 'c': 4, 'b': 3} 

Это использует функции в dict, zip и iter. Преимущество перед Лукашем заключается в том, что он работает для любого итерабельного. Как это работает:

  1. iter(t) создает итератор списка t.
  2. [iter(t)] * 2 создает список с двумя элементами, которые ссылаются на один и тот же итератор.
  3. zip - это функция, которая принимает два итерабельных объекта и объединяет их элементы: первые элементы вместе, другие элементы вместе и т. Д. До тех пор, пока не будет исчерпан один итерабель.
  4. zip(*([iter(t)] * 2)) вызывает тот же самый итератор над t, который должен быть передан как как до zip. Таким образом, zip возьмет первый и второй элемент t и соедините их. А потом третий и четвертый. А затем пятый и шестой и т. Д.
  5. dict берет итерационный номер, содержащий (key, value) пары и создает из них изгиб.
  6. dict(zip(*([iter(t)] * 2))) создает словарь по запросу ОП.
+0

Этот (и все остальные ответы) не кажутся особенно элегантными. Нет встроенного способа? –

+0

Нет единой функции, о которой я знаю, извините. – Stephan202

6

Ребята, ребята, используйте itertools. Ваши пользователи с низким ОЗУ будут благодарны вам, когда списки станут большими.

>>> from itertools import izip, islice 
>>> t = ['a',2,'b',3,'c',4] 
>>> s = dict(izip(islice(t, 0, None, 2), islice(t, 1, None, 2))) 
>>> s 
{'a': 2, 'c': 4, 'b': 3} 

Это может показаться не совсем красивым, но это не сделает ненужные копии в памяти.

+0

Действительно, в Python 2 нужно использовать 'itertools'. Однако в Python 3 'zip' возвращает генератор. В этом случае 'dict (zip (* ([iter (t)] * 2)))' будет делать то же самое. – Stephan202

+0

Поскольку исходный вопрос использовал 'print s', а не' print (s) 'Я предполагал, что Python 2 :) –

+0

Это кажется более сложным, чем было бы необходимо, но я ценю отсутствие копий в памяти =) –

2

Использование stream модуля:

>>> from stream import chop 
>>> t = ['a',2,'b',3,'c',4] 
>>> s = t >> chop(2) >> dict 
>>> s 
{'a': 2, 'c': 4, 'b': 3} 

Следует отметить, что этот модуль является довольно неясным и на самом деле не «играть по правилам» от того, что обычно считается политкорректным Python. Поэтому, если вы просто изучаете Python, не пройдите этот маршрут; придерживаться того, что находится в стандартной библиотеке.

 Смежные вопросы

  • Нет связанных вопросов^_^