2010-01-03 37 views
15

C'è un modo per mappare un elenco su un dizionario? Quello che voglio fare è dargli una funzione che restituirà il nome di una chiave, e il valore sarà il valore originale. Per esempio;Lista mappa sul dizionario

somefunction(lambda a: a[0], ["hello", "world"]) 
=> {"h":"hello", "w":"world"} 

(Questo non è un esempio specifico che voglio fare, voglio una funzione di generico come map() che può fare questo)

risposta

22

non credo esista una funzione standard che fa esattamente questo , ma è molto facile da costruire uno usando il dict incorporato e la comprensione:

def somefunction(keyFunction, values): 
    return dict((keyFunction(v), v) for v in values) 

print somefunction(lambda a: a[0], ["hello", "world"]) 

uscita:

{'h': 'hello', 'w': 'world'} 

Ma trovare un buon nome per questa funzione è più difficile che implementarlo. Lo lascerò come esercizio per il lettore.

+0

Sto usando questo in un programma open source, sotto una licenza in stile BSD. Ti ho dato credito, voglio solo essere sicuro che tu stia bene con quello? –

+2

Sono d'accordo, ma sono sorpreso che daresti un credito esplicito per un contributo così piccolo. –

+0

@MarkByers, Nizza, grazie! – user1514631

5

Se ho capito bene la tua domanda, io credo che si possa ottenere questo risultato con una combinazione di map, zip, e il dict costruttore:

def dictMap(f, xs) : 
    return dict(zip(map(f, xs), xs) 

E un'implementazione saner:

def dictMap(f, xs) : 
    return dict((f(i), i) for i in xs) 
+0

Questa soluzione funziona anche in 2.7.5. –

22

In Python 3 puoi usare questa sintassi di comprensione del dizionario:

def foo(somelist): 
    return {x[0]:x for x in somelist} 
+3

Questa sintassi è disponibile anche in python 2.7 –

1

Se si desidera una funzione generale per fare questo, si sta facendo quasi la domanda giusta. Il tuo esempio non specifica cosa succede quando la funzione chiave produce duplicati, comunque. Tieni l'ultimo? Il primo? Vuoi davvero fare un elenco di tutte le parole che iniziano con la stessa lettera? Queste domande probabilmente rispondono meglio all'utente della funzione, non dal progettista.

La parametrizzazione di questi risultati in una funzione più complessa, ma molto generale. Qui è uno che ho usato per diversi anni:

def reduce_list(key, update_value, default_value, l): 
    """Reduce a list to a dict. 

    key :: list_item -> dict_key 
    update_value :: key * existing_value -> updated_value 
    default_value :: initial value passed to update_value 
    l :: The list 

    default_value comes before l. This is different from functools.reduce, 
    because functools.reduce's order is wrong. 
    """ 
    d = {} 
    for k in l: 
     j = key(k) 
     d[j] = update_value(k, d.get(j, default_value)) 
    return d 

Poi si può scrivere la funzione dicendo:

reduce_list(lambda s:s, lambda s,old:s[0], '', ['hello', 'world']) 
# OR 
reduce_list(lambda s:s, lambda s,old: old or s[0], '', ['hello', 'world']) 

A seconda se si desidera mantenere la prima o l'ultima parola a cominciare, per esempio, 'h'.

Questa funzione è molto generale, però, così la maggior parte del tempo che è la base per altre funzioni, come la group_dict o histogram:

def group_dict(l): 
    return reduce_list(lambda x:x, lambda x,old: [x] + old, [], l) 
def histogram(l): 
    return reduce_list(lambda x:x, lambda x,total: total + 1, 0, l) 
1
>>> dict((a[0], a) for a in "hello world".split()) 
{'h': 'hello', 'w': 'world'} 

Se si desidera utilizzare una funzione invece di indicizzazione, utilizzare operator.itemgetter:

>>> from operator import itemgetter 
>>> first = itemgetter(0) 
>>> dict((first(x), x) for x in "hello world".split()) 
{'h': 'hello', 'w': 'world'} 

O come una funzione:

>>> dpair = lambda x : (first(x), x) 
>>> dict(dpair(x) for x in "hello world".split()) 
{'h': 'hello', 'w': 'world'} 

Infine, se si desidera più di una parola per lettera come possibilità, utilizzare le raccolte.defaultdict

>>> from collections import defaultdict 
>>> words = defaultdict(set) 
>>> addword = lambda x : words[first(x)].add(x) 
>>> for word in "hello house home hum world wry wraught".split(): 
     addword(word) 


>>> print words['h'] 
set(['house', 'hello', 'hum', 'home']) 
0

Prendere suggerimenti da altre risposte L'ho ottenuto utilizzando l'operazione mappa. Non sono sicuro che questo risponda esattamente alla tua domanda.

mylist = ["hello", "world"] 
def convert_to_dict(somelist): 
    return dict(map(lambda x: (x[0], x), somelist)) 

final_ans = convert_to_dict(mylist) 
print final_ans 
Problemi correlati