Python: devuelve la primera clave N: pares de valores de dict

108

Considere el siguiente diccionario, d:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Quiero devolver la primera clave N: pares de valor de d (N <= 4 en este caso). ¿Cuál es el método más eficaz para hacer esto?

Jason Strimpel
fuente
1
Precaución. Parece haber mucha desinformación en las respuestas. Mis pruebas muestran que ni una sola solución es más rápida que list(d.items())[:4]. list () es la implementación subyacente para muchas de las respuestas.
BSalita

Respuestas:

114

No existen las "primeras n" teclas porque a dictno recuerda qué teclas se insertaron primero.

Usted puede obtener cualquier pares de clave y valor n sin embargo:

n_items = take(n, d.iteritems())

Esto utiliza la implementación de takelas itertoolsrecetas :

from itertools import islice

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

Véalo funcionando en línea: ideone


Actualización para Python 3.6

n_items = take(n, d.items())
Mark Byers
fuente
42
Creo que iteritemsdebería ser reemplazado por itemspara la gente en Python 3
Monica Heddneck
1
@MonicaHeddneck, genial, gracias por agregar este comentario.
Karl Baker
12
Principiante aquí: ¿es take()parte de la base del código de Python en algún lugar? ¿O es simplemente la función que definió en su respuesta aquí? Preguntando como si fuera parte del código base, no puedo encontrarlo / importarlo. :)
Scott Borden
81

Una forma muy eficaz de recuperar cualquier cosa es combinar las comprensiones de listas o diccionarios con la división. Si no necesita ordenar los elementos (solo quiere n pares aleatorios), puede usar una comprensión de diccionario como esta:

# Python 2
first2pairs = {k: mydict[k] for k in mydict.keys()[:2]}
# Python 3
first2pairs = {k: mydict[k] for k in list(mydict)[:2]}

Generalmente, una comprensión como esta es siempre más rápida de ejecutar que el ciclo equivalente "para x en y". Además, al usar .keys () para hacer una lista de las claves del diccionario y dividir esa lista, evita 'tocar' las teclas innecesarias cuando crea el nuevo diccionario.

Si no necesita las claves (solo los valores), puede usar una lista de comprensión:

first2vals = [v for v in mydict.values()[:2]]

Si necesita los valores ordenados según sus claves, no hay mucho más problema:

first2vals = [mydict[k] for k in sorted(mydict.keys())[:2]]

o si también necesita las llaves:

first2pairs = {k: mydict[k] for k in sorted(mydict.keys())[:2]}
monotasker
fuente
2
Esta es una mejor solución si desea seleccionar N muchos pares clave: valor como un diccionario, no como una lista
fermat4214
1
@ fermat4214 ¿Es un problema si mi diccionario completo se imprime cuando ejecuto alguno de estos comandos?
Ted Taylor of Life
list (mydict) [: 2] es un desperdicio si no necesita ordenar el diccionario y solo necesita los primeros 2 elementos. ¿Qué pasa si el diccionario tiene pares de 1 mil kv? Convertir todo en una lista es caro. La solución de Mark Byers es mucho mejor.
JJ
¡Esta debería ser la solución!
Guenter
14

Los dicts de Python no están ordenados, por lo que no tiene sentido pedir las "primeras N" claves.

La collections.OrderedDictclase está disponible si eso es lo que necesita. Puede obtener de manera eficiente sus primeros cuatro elementos como

import itertools
import collections

d = collections.OrderedDict((('foo', 'bar'), (1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')))
x = itertools.islice(d.items(), 0, 4)

for key, value in x:
    print key, value

itertools.islicele permite tomar perezosamente una porción de elementos de cualquier iterador. Si desea que el resultado sea reutilizable, deberá convertirlo en una lista o algo así:

x = list(itertools.islice(d.items(), 0, 4))
Jeremy
fuente
Sin parecer perezoso. Toma 2 veces más que `list (d.items ()) [: 4]
BSalita
12
foo = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5, 'f':6}
iterator = iter(foo.items())
for i in range(3):
    print(next(iterator))

Básicamente, convierta la vista (dict_items) en un iterador y luego itere con next ().

cop4587
fuente
2
Respuesta fantástica, esta es la única respuesta en esta página que funcionó para mí y también es legible. Además, puedo verificar que esto funciona con Python 3, que algunas de las respuestas más antiguas no parecen hacerlo.
cdahms
7

No lo vi aquí. No se ordenará, sino que será sintácticamente más simple si solo necesita tomar algunos elementos de un diccionario.

n = 2
{key:value for key,value in d.items()[0:n]}
usuario2623954
fuente
7
Probé su código pero me sale este error: TypeError: 'dict_items' object is not subscriptable {key:value for key,value in stocks.items()[0:n]} (existencias es el nombre de mi diccionario)
Moondra
2
@Moondra: debe realizar la conversión a la lista antes de ejecutar los elementos del diccionario. Por encima del código, la línea funciona si {clave: valor para clave, valor en la lista (d.items ()) [0: n]}
Rajesh Mappu
{A: N para (A, N) en [x para x en d.items ()] [: 4]}
farid khafizov
6

Para obtener los N elementos principales de su diccionario de Python, se puede usar la siguiente línea de código:

list(dictionaryName.items())[:N]

En tu caso puedes cambiarlo a:

list(d.items())[:4]
thevatsalsaglani
fuente
3

Consulte PEP 0265 sobre la clasificación de diccionarios. Luego use el código iterable mencionado anteriormente.

Si necesita más eficiencia en los pares clave-valor ordenados. Utilice una estructura de datos diferente. Es decir, uno que mantiene el orden ordenado y las asociaciones clave-valor.

P.ej

import bisect

kvlist = [('a', 1), ('b', 2), ('c', 3), ('e', 5)]
bisect.insort_left(kvlist, ('d', 4))

print kvlist # [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
silverjam
fuente
3

en py3, esto hará el truco

{A:N for (A,N) in [x for x in d.items()][:4]}

{'a': 3, 'b': 2, 'c': 3, 'd': 4}

Farid Khafizov
fuente
2

solo agrega una respuesta usando zip,

{k: d[k] for k, _ in zip(d, range(n))}
Peter Li
fuente
1

Esto depende de lo que sea "más eficiente" en su caso.

Si solo desea una muestra semi-aleatoria de un diccionario enorme foo, use foo.iteritems()y tome tantos valores como necesite, es una operación perezosa que evita la creación de una lista explícita de claves o elementos.

Si necesita ordenar las claves primero, no hay forma de evitar usar algo como keys = foo.keys(); keys.sort()osorted(foo.iterkeys()) , tendrá que crear una lista explícita de claves. Entonces rebanar o iterar a través de primera N keys.

Por cierto, ¿por qué te preocupas por la forma "eficiente"? ¿Hiciste un perfil de tu programa? Si no lo hizo, utilice primero la forma obvia y fácil de entender . Es probable que funcione bastante bien sin convertirse en un cuello de botella.

9000
fuente
Esta fue una aplicación para un programa financiero e intento construir cada línea de código de la manera más eficiente posible. No hice un perfil del programa y estoy de acuerdo en que probablemente no será un cuello de botella, pero me gusta pedir soluciones eficientes por defecto. Gracias por la respuesta.
Jason Strimpel
0

Puede abordar esto de varias maneras. Si el orden es importante, puede hacer esto:

for key in sorted(d.keys()):
  item = d.pop(key)

Si el orden no le preocupa, puede hacer esto:

for i in range(4):
  item = d.popitem()
gddc
fuente
En el primer fragmento probablemente debería llamarlo en valuelugar de itempara mayor claridad.
2011
0

El diccionario no mantiene ningún orden, por lo que antes de elegir los N pares de valores clave principales, hagámoslo ordenar.

import operator
d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
#itemgetter(0)=sort by keys, itemgetter(1)=sort by values

Ahora podemos hacer la recuperación de los elementos 'N' superiores :, usando la estructura del método como esta:

def return_top(elements,dictionary_element):
    '''Takes the dictionary and the 'N' elements needed in return
    '''
    topers={}
    for h,i in enumerate(dictionary_element):
        if h<elements:
            topers.update({i:dictionary_element[i]})
    return topers

para obtener los 2 elementos superiores, simplemente use esta estructura:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4}
d=dict(sorted(d.items(),key=operator.itemgetter(1),reverse=True))
d=return_top(2,d)
print(d)
Jyothish Arumugam
fuente
0

Para Python 3 y superior, para seleccionar los primeros n pares

n=4
firstNpairs = {k: Diction[k] for k in list(Diction.keys())[:n]}
Shivpe_R
fuente
0

considerar un dictado

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

from itertools import islice
n = 3
list(islice(d.items(),n))

islice hará el truco :) espero que ayude!

Vivek Ananthan
fuente
0

Puede que esto no sea muy elegante, pero funciona para mí:

d = {'a': 3, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

x= 0
for key, val in d.items():
    if x == 2:
        break
    else:
        x += 1
        # Do something with the first two key-value pairs
Thorsten Stehlik
fuente
0

Probé algunas de las respuestas anteriores y noté que algunas de ellas dependen de la versión y no funcionan en la versión 3.7.

También observo que desde 3.6 todos los diccionarios están ordenados por la secuencia en la que se insertan los elementos.

A pesar de que los diccionarios se ordenaron desde 3.6, algunas de las declaraciones que espera que funcionen con estructuras ordenadas no parecen funcionar.

La respuesta a la pregunta de OP que mejor funcionó para mí.

itr = iter(dic.items())
lst = [next(itr) for i in range(3)]
Mark Kortink
fuente
FYI, 5 veces más lento quelst = list(d.items())[:N]
BSalita