2012-08-10 44 views
12

d1 sözlüğünde ve l1 numaralı listeden bir ürün var.Python sözlükte anlama çok yavaş

Sözlük anahtarları dizelerdir ve değerler, kendim tanımladığım Nesnelerdir. Eğer yardımcı olursa, Nesneyi daha ayrıntılı olarak tanımlayabilirim ancak şimdilik, nesnelerin bir names liste özniteliği vardır ve name öğelerinin bazıları l1'da görünebilir veya görünmeyebilir. Yapmak istediğim ne

sözü elemanda nesnenin name nitelik l1 görünen unsurların hiçbirini içermiyor hangi sözlüğe d1, herhangi bir unsur atmak oldu.

Önemsiz bir örnek olarak:

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

böylece elde edilen sözlük olacak aşağı yukarı aynı ancak her liste elemanları meyve ve sebze dışında 4 için 1 anahtar değer çiftlerini olacaktır, ve mobilya değerlerinin hiçbiri l1'da görünmediğinden 5. anahtar/değer çiftini içermeyecektir.

Bunu yapmak için ben böyle görünüyordu yuvalanmış liste/Sözlük anlama kullandı:

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

Bu iş gibi görünüyor, ama büyük sözlüklerde, 7000+ öğeler için, üzerinden çalışmak için yaklaşık 20 saniye sürer. Kendi başına, korkunç değil, ama bunu 10.000 kez yineleyecek bir döngü içinde yapmam gerekiyor, bu yüzden şu anda mümkün değil. Bunu nasıl yapılacağına dair herhangi bir öneriniz var mı?

+1

Not: O 'baskı izin vermeyin nedeniyle itertitems'' kullanımına piton 2.7 değil 3 kullanıyor() fool – jamylak

+0

python 2.7 dict anlayışları var mı? – Claudiu

+0

@Claudiu Evet, tamamen kopyalanabilir örnek sağlamak için – jamylak

cevap

13

l1 listesindeki sözlük değerlerinde oluşan her bir listenin kesişim kümesini etkin bir şekilde hesaplıyorsunuz. Kesişen kesişme listeleri kullanmak, ilgili lineer aramalar nedeniyle oldukça verimsizdir. l1'u bir gruba dönüştürmeli ve set.intersection()'u kullanmalı veya bunun yerine üyelik testlerini ayarlamalısınız (sonucun tekrar ayarlanmasının kabul edilip edilmediğine bağlı olarak).

tam kod aşağıdaki gibi görünebilir: Yerine iki Sözlük anlayışların

l1 = set(l1) 
d2 = {k: [s for s in v if s in l1] for k, v in d1.iteritems()} 
d2 = {k: v for k, v in d2.iteritems() if v} 

, o da burada tek for döngü kullanılması tercih olabilir:

l1 = set(l1) 
d2 = {} 
for k, v in d1.iteritems(): 
    v = [s for s in v if s in l1] 
    if v: 
     d2[k] = v 
+0

Tam verimlilik için ilk kodunuzu >>>> d2 = ((k için [s için l lerde ls içinde ls] durumunda) k, v d1.iteritems() için değiştiririm >>> d2 = {k: v için k, v için d2'de v}. – jamylak

+0

@jamylak: Bunun, 'for' döngüsünden daha hızlı olacağına inanıyor musunuz? Ben bir tane için en az notoicably çirkin olduğunu düşünüyorum. :) –

+0

Peki, şu anda ilk kodunuz için sahip olduğunuz koddan daha verimli olacak. İkinciden emin değilim, 'timeit' – jamylak

4

sorun değil Dict anlama, ancak iç içe liste anlama. Her seferinde aynı tuşların üzerinde yineliyorsunuz. Bu tür şeyler setlerle daha iyi yapılır.

s1 = set(l1) 
d2 = {k: list(s1.intersection(v)) for k, v in d1.items()} 
+2

için daha fazla verimlilik kullanmak için 'iteritems' – jamylak

+1

' d1' ve' d2' içindeki değerlerin kümeler olmasına izin verilirse daha verimli olacaktır. –

0

Kullanım set: Bir set için l1 dönüştürmek ve hafifçe dict anlama değiştirirseniz

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

, bu çalışma kabaca üç kat daha hızlı alabilirsiniz: Burada

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) 

nasıl Performansı değerlendirebilirsiniz:

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) 

Burada, d1 üzerinde denetiminiz olmadığını ve d1 tüm değerlerini filtrelemeden önce ayarlamaya dönüştürdüğünüzü varsayıyorum.

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

Çıktı: Alternatif

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

: herkese

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