2009-08-06 12 views
5

pregunta de novato aquí, así que por favor tengan paciencia conmigo.Cómo filtrar un diccionario por valor?

Digamos que tengo un diccionario con este aspecto:

a = {"2323232838": ("first/dir", "hello.txt"), 
    "2323221383": ("second/dir", "foo.txt"), 
    "3434221": ("first/dir", "hello.txt"), 
    "32232334": ("first/dir", "hello.txt"), 
    "324234324": ("third/dir", "dog.txt")} 

Quiero que todos los valores que son iguales entre sí para ser trasladado a otro diccionario.

matched = {"2323232838": ("first/dir", "hello.txt"), 
      "3434221": ("first/dir", "hello.txt"), 
      "32232334": ("first/dir", "hello.txt")} 

Y los restantes elementos no coincidentes debe buscar la siguiente manera:

remainder = {"2323221383": ("second/dir", "foo.txt"), 
      "324234324": ("third/dir", "dog.txt")} 

Gracias de antemano, y si se proporciona un ejemplo, por favor comentar tanto como sea posible.

+0

Como han dicho los demás, simplemente no puede tener diccionarios como los que da en sus ejemplos. Tiene varios valores de unique_id, dir y file, y eso simplemente no es legal. Las claves del diccionario son únicas. –

+0

OH! Lo siento, lo siento, lo corregiré. –

+0

Su corrección ahora no es ni siquiera sintácticamente correcta Python. Quizás podría preguntar "¿Cómo representaría los siguientes datos en las estructuras de datos de Python?" y luego describe tus datos. –

Respuesta

1

iteración en un diccionario no es diferente de la iteración en una lista en Python:

for key in dic: 
    print("dic[%s] = %s" % (key, dic[key])) 

Esto imprimirá todas las claves y los valores de su diccionario.

+0

Mientras tiene razón, esto se manejó en los comentarios y no responde a su pregunta, que fue deducible. – Triptych

1

Supongo que su identificación única será la clave.
Probablemente no muy bonito, pero devuelve un diccionario con sus valores únicos:

>>> dict_ = {'1': ['first/dir', 'hello.txt'], 
'3': ['first/dir', 'foo.txt'], 
'2': ['second/dir', 'foo.txt'], 
'4': ['second/dir', 'foo.txt']} 
>>> dict((v[0]+v[1],k) for k,v in dict_.iteritems()) 
{'second/dir/foo.txt': '4', 'first/dir/hello.txt': '1', 'first/dir/foo.txt': '3'} 

que he visto que actualizó su mensaje:

>>> a 
{'324234324': ('third/dir', 'dog.txt'), 
'2323221383': ('second/dir', 'foo.txt'), 
'3434221': ('first/dir', 'hello.txt'), 
'2323232838': ('first/dir', 'hello.txt'), 
'32232334': ('first/dir', 'hello.txt')} 
>>> dict((v[0]+"/"+v[1],k) for k,v in a.iteritems()) 
{'second/dir/foo.txt': '2323221383', 
'first/dir/hello.txt': '32232334', 
'third/dir/dog.txt': '324234324'} 
+0

eso no es lo que OP ha pedido en absoluto. – SilentGhost

+0

Como el tuyo no lo es, también. El OP tenía una versión diferente al principio que me confundió. La versión de Tryptichs parece estar bien, sin embargo. – buster

10

El código siguiente se traducirá en dos variables, y matchesremainders. matches es una matriz de diccionarios en la que los elementos coincidentes del diccionario original tendrán un elemento correspondiente. remainder contendrá, como en su ejemplo, un diccionario que contiene todos los elementos no coincidentes.

Tenga en cuenta que en su ejemplo, solo hay un conjunto de valores coincidentes: ('first/dir', 'hello.txt'). Si hubiera más de un conjunto, cada uno tendría una entrada correspondiente en matches.

import itertools 

# Original dict 
a = {"2323232838": ("first/dir", "hello.txt"), 
    "2323221383": ("second/dir", "foo.txt"), 
    "3434221": ("first/dir", "hello.txt"), 
    "32232334": ("first/dir", "hello.txt"), 
    "324234324": ("third/dir", "dog.txt")} 

# Convert dict to sorted list of items 
a = sorted(a.items(), key=lambda x:x[1]) 

# Group by value of tuple 
groups = itertools.groupby(a, key=lambda x:x[1]) 

# Pull out matching groups of items, and combine items 
# with no matches back into a single dictionary 
remainder = [] 
matched = [] 

for key, group in groups: 
    group = list(group) 
    if len(group) == 1: 
     remainder.append(group[0]) 
    else: 
     matched.append(dict(group)) 
else: 
    remainder = dict(remainder) 

Salida:

>>> matched 
[ 
    { 
    '3434221': ('first/dir', 'hello.txt'), 
    '2323232838': ('first/dir', 'hello.txt'), 
    '32232334': ('first/dir', 'hello.txt') 
    } 
] 

>>> remainder 
{ 
    '2323221383': ('second/dir', 'foo.txt'), 
    '324234324': ('third/dir', 'dog.txt') 
} 

Como novato, que probablemente está siendo introducido a unos pocos conceptos desconocidos en el código de seguridad. Estos son algunos enlaces:

+0

agradable. Puedo ver ahora que interpreté mal la pregunta con mi respuesta. De todos modos, se ve bien :) – buster

+0

Gracias, tendré que leer sobre grupos, pero eso está bien, gracias un millón. ¡También gracias por editar mi pregunta! –

+0

Nota, len (grupo) es 1 debe leer len (grupo) == 1. Mientras que la prueba de identidad ("es") funciona aquí en cPython debido a un pequeño almacenamiento en caché entero, es un mal hábito entrar. Quieres una prueba de igualdad. –

0

si sabe cuál es el valor que desea filtrar:

known_tuple = 'first/dir','hello.txt' 
b = {k:v for k, v in a.items() if v == known_tuple} 

luego se convertiría en a:

a = dict(a.items() - b.items()) 

esta es la notación py3k, pero estoy seguro de que algo similar se puede implementar en versiones heredadas. Si no sabe qué es known_tuple, primero debe averiguarlo. por ejemplo, así:

c = list(a.values()) 
for i in set(c): 
    c.remove(i) 
known_tuple = c[0] 
+0

No, puede ser "third/dir", "something.txt", no sé. –

4

Lo que están pidiendo que se llama un "índice invertido" - los elementos distintos se registraron sólo una vez con una lista de claves.

>>> from collections import defaultdict 
>>> a = {"2323232838": ("first/dir", "hello.txt"), 
...  "2323221383": ("second/dir", "foo.txt"), 
...  "3434221": ("first/dir", "hello.txt"), 
...  "32232334": ("first/dir", "hello.txt"), 
...  "324234324": ("third/dir", "dog.txt")} 
>>> invert = defaultdict(list) 
>>> for key, value in a.items(): 
...  invert[value].append(key) 
... 
>>> invert 
defaultdict(<type 'list'>, {('first/dir', 'hello.txt'): ['3434221', '2323232838', '32232334'], ('second/dir', 'foo.txt'): ['2323221383'], ('third/dir', 'dog.txt'): ['324234324']}) 

El diccionario invertido tiene los valores originales asociados con una lista de 1 o más teclas.

Ahora, para obtener sus diccionarios revisados ​​de este.

Filtrado:

>>> [ invert[multi] for multi in invert if len(invert[multi]) > 1 ] 
[['3434221', '2323232838', '32232334']] 
>>> [ invert[uni] for uni in invert if len(invert[uni]) == 1 ] 
[['2323221383'], ['324234324']] 

Ampliación

>>> [ (i,multi) for multi in invert if len(invert[multi]) > 1 for i in invert[multi] ] 
[('3434221', ('first/dir', 'hello.txt')), ('2323232838', ('first/dir', 'hello.txt')), ('32232334', ('first/dir', 'hello.txt'))] 
>>> dict((i,multi) for multi in invert if len(invert[multi]) > 1 for i in invert[multi]) 
{'3434221': ('first/dir', 'hello.txt'), '2323232838': ('first/dir', 'hello.txt'), '32232334': ('first/dir', 'hello.txt')} 

Un tratamiento similar (pero más simple) trabaja para los artículos que se producen una vez.

+0

Huh, muy simple, tengo que usar el lib de python estándar. más, gracias por esto. –

+0

Ah, bien, también. Es increíble lo que puedes hacer con llamadas estándar simples :) – buster

Cuestiones relacionadas