Conversión de una sola lista ordenada en python a un diccionario, pythonically

Parece que no puedo encontrar una manera elegante de comenzar desde t y dar como resultado s .

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

Las soluciones que he encontrado que parecen menos que elegantes:

 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 

Obviamente, se resuelve fácilmente, pero, una vez más, parece que hay una mejor manera. ¿Esta ahí?

Lo itertools , pero si crees que es complicado (como has sugerido en un comentario), entonces tal vez:

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

o equivalentemente, y de nuevo a itertools,

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

o, si insiste en estar en línea, en un estado de ánimo de “truco o trato” apropiado para la temporada:

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

yo, considero que esto es un truco, pero algunos pueden encontrarlo como un regalo. IOW, encuentro este tipo de cosas que dan miedo, pero aparentemente en los Estados Unidos en esta época de los años se supone que las cosas son ;-).

Básicamente, el problema se reduce a “cómo recorro una lista de 2 elementos a la vez”, porque dict está bastante contento de tomar una secuencia de 2 tuplas y convertirla en un diccionario. Todas las soluciones que muestro aquí aseguran que solo se toma O(1) espacio adicional (más allá del espacio, obviamente O(N) , que es necesario para la lista de entrada y el dictado de salida, por supuesto).

El enfoque sugerido en los documentos (todos deben estar familiarizados con esa página, las recetas de itertool) es la función de pairwise en esa página, que es básicamente la segunda que sugerí aquí. Creo que cada directorio de paquetes de sitio debe contener un archivo iterutils.py con esas recetas (¡lástima que este archivo ya no sea parte de la plantilla de Python! -).

La misma idea que la respuesta de Lukáš Lalinský , idioma diferente:

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

Esto utiliza las funciones dict , zip e iter . La ventaja sobre la respuesta de Lukáš es que funciona para cualquier iterable. Cómo funciona:

  1. iter(t) crea un iterador sobre la lista t .
  2. [iter(t)] * 2 crea una lista con dos elementos, que hacen referencia al mismo iterador.
  3. zip es una función que toma dos objetos iterables y empareja sus elementos: los primeros elementos juntos, los segundos elementos juntos, etc., hasta que uno se agota.
  4. zip(*([iter(t)] * 2)) hace que el mismo iterador sobre t se pase como ambos argumentos a zip . zip tomará el primer y segundo elemento de t y los emparejará. Y luego el tercero y cuarto. Y luego la quinta y sexta, etc.
  5. dict toma un iterable que contiene pares (key, value) y crea un dctionary a partir de ellos.
  6. dict(zip(*([iter(t)] * 2))) crea el diccionario según lo solicitado por el OP.

No es exactamente eficiente, pero si no lo necesita para listas muy grandes:

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

O tu versión utilizando un generador:

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

Chicos, chicos, usen itertools. Sus usuarios con poca memoria RAM se lo agradecerán cuando las listas crezcan.

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

Puede que no se vea bonito, pero no hará copias innecesarias en memoria.

Usando el módulo de flujo :

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

Cabe señalar que este módulo es bastante oscuro y en realidad no “cumple con las reglas” de lo que típicamente se considera Python políticamente correcto. Así que si solo estás aprendiendo Python, no sigas esta ruta; se adhieren a lo que está en la biblioteca estándar.

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

Probablemente no sea el más eficiente. trabaja en python 3; puede que necesites importar zip, en python 2.x