Mam słownik d1 i listę l1.

Klucze słownikowe są ciągi, a wartości są obiektami, które się zdefiniowałem. Jeśli pomoże, mogę opisać obiekt bardziej szczegółowo, ale na razie obiekty mają atrybut listy names, a niektóre elementy name mogą lub mogą pojawić się w l1 .

Chciałem zrobić, to wyrzucić dowolny element słownika d1, w którym atrybut name obiektu w tym elemencie nie zawiera żadnych elementów, które pojawiają się w l1 .

Jako trywialny przykład:

l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant', 
      'zebra', 'lion', 'snake', 'fly']

d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
      '2':['apple', 'pear','cat', 'mouse', 'horse'], 
      '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
      '4':['carrot','potato','cat', 'dog', 'horse'], 
      '5':['chair', 'table', 'knife']}

Więc wynikowy słownik będzie mniej więcej taki sam, ale elementy każdej listy będą parami kluczowymi parami od 1 do 4 z wyłączeniem owoców i warzyw i nie zawierają 5 klawisza Wartość par, ponieważ żadna z wartości mebli pojawiają się w l1.

Aby to zrobić, użyłem zagnieżdżonej listy / rozumienia słownika, które wyglądały tak:

d2 = {k: [a for a in l1 if a in d1[k]] for k in d1.keys()}
print(d2)

>>>>{'1': ['dog', 'mouse', 'horse'], 
     '3': ['cat', 'dog', 'mouse'], 
     '2': ['cat', 'mouse', 'horse'], 
     '5': [], 
     '4': ['cat', 'dog', 'horse']}

d2 = {k: v for k,v in d2.iteritems() if len(v)>0}
print(d2)

>>>>{'1': ['dog', 'mouse', 'horse'], 
     '3': ['cat', 'dog', 'mouse'], 
     '2': ['cat', 'mouse', 'horse'],  
     '4': ['cat', 'dog', 'horse'],}

Wydaje się, że działa, ale dla dużych słowników, 7000+ przedmiotów trwa około 20 sekund. W sobie, niezbyt okropnie, ale muszę zrobić to wewnątrz pętli, która spowoduje 10 000 razy, więc obecnie nie jest to możliwe. Jakieś sugestie, jak szybko zrobić to szybko?

14
Davy Kavanagh 10 sierpień 2012, 18:03

4 odpowiedzi

Problemem nie jest dict rozumienia, ale zagnieżdżona lista zrozumienia w tym. ITeresting nad tym samym klucze za każdym razem. Ten rodzaj rzeczy jest lepszy z zestawami.

s1 = set(l1)
d2 = {k: list(s1.intersection(v)) for k, v in d1.items()}
4
Daniel Roseman 10 sierpień 2012, 14:11
l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant', 
      'zebra', 'lion', 'snake', 'fly']

d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
      '2':['apple', 'pear','cat', 'mouse', 'horse'], 
      '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
      '4':['carrot','potato','cat', 'dog', 'horse'], 
      '5':['chair', 'table', 'knife']}

def gen_items(valid_name_set, d):
    for k, v in d.iteritems():
        intersection = valid_name_set.intersection(v)
        if intersection: # not empty
            yield (k, intersection)

print dict(gen_items(set(l1), d1))

Wynik:

{'1': set(['dog', 'horse', 'mouse']),
 '2': set(['cat', 'horse', 'mouse']),
 '3': set(['cat', 'dog', 'mouse']),
 '4': set(['cat', 'dog', 'horse'])}

Alternatywnie:

from itertools import ifilter
from operator import itemgetter
set_l1 = set(l1)
d2 = dict(ifilter(itemgetter(1), 
                  ((k, set_l1.intersection(v)) for k, v in d1.iteritems())))
1
jamylak 10 sierpień 2012, 14:45

Użyj set:

>>> l1 = ['cat', 'dog', 'mouse', 'horse', 'elephant',
      'zebra', 'lion', 'snake', 'fly']
>>> d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
      '2':['apple', 'pear','cat', 'mouse', 'horse'],
      '3':['kiwi', 'lime','cat', 'dog', 'mouse'],
      '4':['carrot','potato','cat', 'dog', 'horse'],
      '5':['chair', 'table', 'knife']}
>>> l1_set = set(l1)
>>> d2 = dict((k, set(d1[k]) & l1_set) for k in d1.keys())
>>> d2
{'1': set(['horse', 'mouse', 'dog']), '3': set(['mouse', 'dog', 'cat']), '2': set(['horse', 'mouse', 'cat']), '5': set([]), '4': set(['horse', 'dog', 'cat'])}
>>> d2 = dict((k, v) for k,v in d2.iteritems() if v)
>>> d2
{'1': set(['horse', 'mouse', 'dog']), '3': set(['mouse', 'dog', 'cat']), '2': set(['horse', 'mouse', 'cat']), '4': set(['horse', 'dog', 'cat'])}
0
Claudiu 10 sierpień 2012, 14:12

Jeśli konwertujesz l1 do set i nieznacznie zmodyfikuj dict rozumienie, możesz uzyskać tę pracę w przybliżeniu trzy razy szybciej:

l1 = set(['cat', 'dog', 'mouse', 'horse', 'elephant', 
      'zebra', 'lion', 'snake', 'fly'])

d1 = {'1':['dog', 'mouse', 'horse','orange', 'lemon'],
      '2':['apple', 'pear','cat', 'mouse', 'horse'], 
      '3':['kiwi', 'lime','cat', 'dog', 'mouse'], 
      '4':['carrot','potato','cat', 'dog', 'horse'], 
      '5':['chair', 'table', 'knife']}

d2 = {k: [a for a in d1[k] if a in l1] for k in d1.keys()}
print(d2)

Oto jak możesz porównać wydajność:

import timeit

t = timeit.Timer(
    "d2 = {k: [a for a in l1 if a in d1[k]] for k in d1.keys()}",
    "from __main__ import (d1, l1)",
    )
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

t = timeit.Timer(
    'd2 = {k: [a for a in d1[k] if a in l1] for k in d1.keys()}',
    "from __main__ import (d1, l1)",
    )
print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)

Zakładam tutaj, że nie masz kontroli nad d1, i to przekształcanie wszystkich wartości d1 do ustawień przed filtrem jest zbyt wolny.

0
Daniel Nouri 10 sierpień 2012, 14:17