2009-08-06 27 views
5

Domanda newbie qui, quindi per favore abbiate pazienza con me.Come filtrare un dizionario per valore?

Diciamo che ho un dizionario simile a questo:

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

Voglio tutti i valori che sono uguali tra loro per essere spostato in un altro dizionario.

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

E i restanti elementi non corrispondenti dovrebbe essere simile a questo:

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

Grazie in anticipo, e se si fornisce un esempio, si prega di commentare il più possibile.

+0

Come gli altri hanno già detto, non puoi semplicemente avere dizionari come quelli che dai nei tuoi esempi. Hai più valori di unique_id, dir e file, e questo non è legale. Le chiavi del dizionario sono uniche. –

+0

OH! Il mio male, mi dispiace per quello, lo correggerò. –

+0

La tua correzione ora non è nemmeno sintatticamente corretta Python. Forse potresti chiedere "Come rappresenterei i seguenti dati nelle strutture dati Python?" e quindi descrivi i tuoi dati. –

risposta

1

l'iterazione di un dizionario non è diverso da l'iterazione di una lista in pitone:

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

Questo stamperà tutte le chiavi e valori del vostro dizionario.

+0

Mentre hai ragione, questo è stato gestito nei commenti, e non risponde alla sua domanda, che era deducibile. – Triptych

1

Suppongo che il tuo ID univoco sarà la chiave.
Probabilmente non molto bella, ma restituisce un dict con i tuoi valori unici:

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

Ho visto aggiornati tuo post:

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

non è quello che l'OP ha chiesto a tutti. – SilentGhost

+0

Come anche il tuo. L'OP aveva una versione diversa all'inizio che mi confondeva. La versione di Tryptichs sembra essere a posto, però. – buster

10

Il codice di seguito si tradurrà in due variabili, matches e remainders. matches è una matrice di dizionari, in cui gli elementi corrispondenti del dizionario originale avranno un elemento corrispondente. remainder conterrà, come nel tuo esempio, un dizionario contenente tutti gli articoli non abbinati.

Si noti che nel proprio esempio esiste un solo set di valori corrispondenti: ('first/dir', 'hello.txt'). Se ci fosse più di un set, ognuno avrebbe una voce corrispondente in 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) 

uscita:

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

Come un principiante, probabilmente siete in fase di introduzione ad alcuni concetti non familiari nel codice sopra. Qui ci sono alcuni link:

+0

bello. Posso vedere ora che ho frainteso la domanda con la mia risposta. Ad ogni modo, mi sta bene :) – buster

+0

Grazie, dovrò leggere i gruppi, ma va tutto bene, grazie mille. Grazie anche per aver modificato la mia domanda! –

+0

Nota, len (gruppo) è 1 dovrebbe leggere len (gruppo) == 1. Mentre il test di identità ("è") funziona qui in cPython a causa del piccolo caching di interi, è una cattiva abitudine entrare. Vuoi un test di uguaglianza. –

0

se si sa quale valore si desidera filtrare:

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

poi a diventerebbe:

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

questa è la notazione py3k, ma sono sicuro che qualcosa simile può essere implementato nelle versioni precedenti. Se non sai cos'è lo known_tuple, devi prima trovarlo. per esempio come questo:

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

No, può benissimo essere "terzo/dir", "qualcosa.txt", non lo so. –

4

Quello che stai chiedendo è chiamato un "Inverted Indice" - gli elementi distinti sono registrati solo una volta con una lista di chiavi.

>>> 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']}) 

Il dizionario invertito ha i valori originali associati a un elenco di 1 o più tasti.

Ora, per ottenere i dizionari revisionati da questo.

Filtering:

>>> [ 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']] 

Espansione

>>> [ (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 simile (ma più semplice) trattamento funziona per le voci che si verificano una volta.

+0

Eh, molto semplice, devo usare la lib di python standard. di più, grazie per questo. –

+0

Ah, bello, anche. È incredibile quello che puoi fare con semplici chiamate standard :) – buster

Problemi correlati