2010-11-16 8 views
7

que tiene un diccionario que tiene muchos elementos, quiero escribir una función que puede devolver los elementos en el rango de índice dado (dict tratar como un array):pitón: cómo conseguir un subconjunto de dict

get_range(dict, begin, end): 
    return {a new dict for all the indexes between begin and end} 

¿Cómo se puede hacer eso?

EDIT: No estoy pidiendo usando el filtro clave ... por ejemplo)

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

get_range(dict, 0, 1) returns {"a":"b", "c":"d"} (the first 2 elements) 

no me importa la clasificación ... En realidad, yo estoy poniendo en práctica la paginación del lado del servidor ...

+2

por __indexes__ te refieres a claves ??? – mouad

+1

@singularity: Al mirar la pregunta pasada de OP http://stackoverflow.com/questions/4181367/python-possible-to-filter-dict, debería tener razón. – kennytm

+0

NO, no por clave, justo después de ordenar (o no ordenar nada), quiero que las primeras/últimas/partes medias del dict ... –

Respuesta

16

Editar: Un diccionario es no ordenado. Es imposible hacer que get_range devuelva la misma porción cada vez que haya modificado el diccionario. Si necesita un resultado determinista, reemplace su dictwith a collections.OrderedDict.

De todos modos, se puede obtener una rebanada using itertools.islice:

import itertools 
def get_range(dictionary, begin, end): 
    return dict(itertools.islice(dictionary.iteritems(), begin, end+1)) 

La respuesta anterior que se filtra por la clave se mantiene por debajo:

Con @Douglas 'algoritmo, podríamos simplificarla mediante el uso de una expresión del generador:

def get_range(dictionary, begin, end): 
    return dict((k, v) for k, v in dictionary.iteritems() if begin <= k <= end) 

BTW, no use dict como el nombre de la variable, como puede ver aquí dict es un constructor de diccionario.

Si está utilizando Python 3.x, puede usar la comprensión del diccionario directamente.

def get_range(dictionary, begin, end): 
    return {k: v for k, v in dictionary.items() if begin <= k <= end} 
+0

Buena solución y aún muy legible. – helpermethod

+0

Llamar a la variable the_dict o tal es el estilo "apropiado" para las variables. –

+0

@Chris: OK. (Renombrado como 'dictionary' para que ambos lados estén contentos :)) – kennytm

3

recta aplicación hacia adelante:

def get_range(d, begin, end): 
    result = {} 
    for (key,value) in d.iteritems(): 
     if key >= begin and key <= end: 
      result[key] = value 
    return result 

Una línea:

def get_range2(d, begin, end): 
    return dict([ (k,v) for (k,v) in d.iteritems() if k >= begin and k <= end ]) 
+2

o: __begin <= key <= end__ – mouad

+1

Eek, * por favor * no llame al parámetro 'dict' ... también' key> = begin y key <= end' sería más nítido como 'begin <= key < = fin'. Función Cool Python, la forma en que puedes hacer eso. –

+0

Solo siguiendo el OP ... Acepto el nombre de la variable incorrecta. –

0

descanso aseguró que lo que realmente quiere un OrderedDict, también se puede utilizar enumerate:

#!/usr/bin/env python 
def get_range(d, begin, end): 
    return dict(e for i, e in enumerate(d.items()) if begin <= i <= end) 

if __name__ == '__main__': 
    print get_range({"a":"b", "c":"d", "e":"f"}, 0, 1) 

de salida:

{'a': 'b', 'c': 'd'} 

PS: Me dejaré usar 0, 1 como valores de rango, pero debe usar 0, 2 para firmar los "primeros dos elementos" (y use begin <= i < end como función de comparación

0

Como han mencionado otros, en Python los diccionarios están inherentemente desordenados. Sin embargo, en cualquier momento dado, se puede obtener una lista de sus claves actuales o pares clave y de valor utilizando sus métodos keys() o items().

Un posible problema con el uso de estas listas es que no solo sus contenidos, sino también el orden en el que se devuelve variarán si el diccionario ha sido modificado (o mutado) desde la última vez que se usaron. Esto significa que generalmente no puede almacenar y reutilizar la lista a menos que la actualice cada vez que se cambia el diccionario, en caso de que la necesite.

Para hacer este enfoque más manejable, puede combinar un diccionario y la lista auxiliar en una nueva clase derivada que se encarga de la sincronización entre los dos y también proporciona un método get_range() que hace uso de los contenidos actuales de la lista. A continuación se muestra un código de muestra que muestra cómo se podría hacer esto. Está basado en ideas que obtuve del código en this ActiveState Python Recipe.

class dict_with_get_range(dict): 
    def __init__(self, *args, **kwrds): 
     dict.__init__(self, *args, **kwrds) 
     self._list_ok = False 

    def _rebuild_list(self): 
     self._list = [] 
     for k,v in self.iteritems(): 
      self._list.append((k,v)) 
     self._list_ok = True 

    def get_range(self, begin, end): 
     if not self._list_ok: 
      self._rebuild_list() 
     return dict(self._list[i] for i in range(begin,end+1)) 

def _wrapMutatorMethod(methodname): 
    _method = getattr(dict, methodname) 
    def wrapper(self, *args, **kwrds): 
     # Reset 'list OK' flag, then delegate to the real mutator method 
     self._list_ok = False 
     return _method(self, *args, **kwrds) 
    setattr(dict_with_get_range, methodname, wrapper) 

for methodname in 'delitem setitem'.split(): 
    _wrapMutatorMethod('__%s__' % methodname) 
for methodname in 'clear update setdefault pop popitem'.split(): 
    _wrapMutatorMethod(methodname) 
del _wrapMutatorMethod # no longer needed 

dct = dict_with_get_range({"a":"b", "c":"d", "e":"f"}) 
print dct.get_range(0, 1) 
# {'a': 'b', 'c': 'd'} 
del dct["c"] 
print dct.get_range(0, 1) 
# {'a': 'b', 'e': 'f'} 

La idea básica consiste en derivar una nueva clase de dict que también tiene una lista de contenido interno para su uso con el nuevo método get_range() que establece que los objetos del diccionario regulares no lo hacen. Para minimizar la necesidad de actualizar (o incluso crear) esta lista interna, también tiene un indicador que indica si la lista está actualizada o no, y solo la revisa y reconstruye la lista cuando sea necesario.

Para mantener el indicador, cada método de diccionario heredado que potencialmente cambie (o muta) los contenidos del diccionario está "envuelto" con la función auxiliar, restablece el indicador y luego encadena al método normal del diccionario para realizar la operación. Instalarlos en la clase es simplemente una cuestión de poner los nombres de los métodos en una de dos listas y luego pasarlos uno por uno a una utilidad auxiliar inmediatamente después de la creación de la clase.

Cuestiones relacionadas