2011-01-25 14 views
1

私は1000項目のPython辞書を持っています。各項目は、それ自体、辞書です。私は各項目を解析するためのきれいでエレガントな方法を探しており、&テンプレートを見つけることができます。ここでPython辞書、類似点を見つけよう

は、個々の辞書構造の単純化した例を示します。このことから

{'id': 1, 
'template': None, 
'height': 80, 
'width': 120, 
'length': 75, 
'weight': 100} 

、私は一度通過したい、と、1000年の500ので、同じ高さと幅を共有することを決定した場合私は、そのデータからテンプレートを構築し、テンプレートIDを 'テンプレート'に割り当てることができます。私は巨大な参照ハッシュを構築することができますが、これを達成するためのより洗練されたより洗練された方法があることを期待しています。

実際のデータには30個近くのキーが含まれ、そのうちの小さいサブセットをテンプレート検査から除外する必要があります。 dicts itemsの辞書を考える

答えて

0

@eumiroは、優れたコアアイデア、バッチで一緒に共通の値を持つアイテムを配置するitertools.groupby()を使用しての、すなわちそれを持っていました。しかし、@Jochen Ritzelが指摘したのと同じ主要な機能を使って最初にソートすることを無視しているだけでなく、ドキュメントにも言及されています。

以下は、より完全で多少長い答えです。それはテンプレートを決定し、dict-of-dictsと考えられる1回のパスでそれらを割り当てる。これを行うには、アイテムのソートされたリストを最初に作成した後、groupby()を使用してバッチ処理を行い、各グループに十分な数があればテンプレートを作成し、各メンバーにそのIDを割り当てます。

inventory = { 
    'item1': {'id': 1, 'template': None, 'height': 80, 'width': 120, 'length': 75, 'weight': 100}, 
    'item2': {'id': 2, 'template': None, 'height': 30, 'width': 40, 'length': 20, 'weight': 20}, 
    'item3': {'id': 3, 'template': None, 'height': 80, 'width': 100, 'length': 96, 'weight': 150}, 
    'item4': {'id': 4, 'template': None, 'height': 30, 'width': 40, 'length': 60, 'weight': 75}, 
    'item5': {'id': 5, 'template': None, 'height': 80, 'width': 100, 'length': 36, 'weight': 33} 
} 

import itertools as itools 

def print_inventory(): 
    print 'inventory:' 
    for key in sorted(inventory.iterkeys()): 
     print ' {}: {}'.format(key, inventory[key]) 

print "-- BEFORE --" 
print_inventory() 

THRESHOLD = 2 
ALLKEYS = ['template', 'height', 'width', 'length', 'weight'] 
EXCLUDEDKEYS = ['template', 'length', 'weight'] 
INCLUDEDKEYS = [key for key in ALLKEYS if key not in EXCLUDEDKEYS] 

# determines which keys make up a template 
sortby = lambda item, keys=INCLUDEDKEYS: tuple(item[key] for key in keys) 

templates = {} 
templateID = 0 
sortedinventory = sorted(inventory.itervalues(), key=sortby) 
for templatetuple, similariter in itools.groupby(sortedinventory, sortby): 
    similaritems = list(similariter) 
    if len(similaritems) >= THRESHOLD: 
     # create and assign a template 
     templateID += 1 
     templates[templateID] = templatetuple # tuple of values of INCLUDEDKEYS 
     for item in similaritems: 
      item['template'] = templateID 
print 
print "-- AFTER --" 
print_inventory() 
print 
print 'templates:', templates 
print 

私はそれを実行すると、次のように出力されます:

-- BEFORE -- 
inventory: 
    item1: {'weight': 100, 'height': 80, 'width': 120, 'length': 75, 'template': None, 'id': 1} 
    item2: {'weight': 20, 'height': 30, 'width': 40, 'length': 20, 'template': None, 'id': 2} 
    item3: {'weight': 150, 'height': 80, 'width': 100, 'length': 96, 'template': None, 'id': 3} 
    item4: {'weight': 75, 'height': 30, 'width': 40, 'length': 60, 'template': None, 'id': 4} 
    item5: {'weight': 33, 'height': 80, 'width': 100, 'length': 36, 'template': None, 'id': 5} 

-- AFTER -- 
inventory: 
    item1: {'weight': 100, 'height': 80, 'width': 120, 'length': 75, 'template': None, 'id': 1} 
    item2: {'weight': 20, 'height': 30, 'width': 40, 'length': 20, 'template': 1, 'id': 2} 
    item3: {'weight': 150, 'height': 80, 'width': 100, 'length': 96, 'template': 2, 'id': 3} 
    item4: {'weight': 75, 'height': 30, 'width': 40, 'length': 60, 'template': 1, 'id': 4} 
    item5: {'weight': 33, 'height': 80, 'width': 100, 'length': 36, 'template': 2, 'id': 5} 

templates: {1: (30, 40), 2: (80, 100)} 
+0

優れています。最初のレスポンスに基づいて、いくつかの概念実証コードをまとめましたが、あなたの答えは私が走っていた問題のいくつかを解決します。ありがとう。この場所を愛する。 – samurailawngnome

3

import itertools as it 

for (height, width), itemIter in it.groupby (items.values(), lambda x: (x['height'], x['width'])): 
    # in list(itemIter) you will find all items with dimensions (height, width) 
+3

GROUPBYは、同じキーを持つ唯一のグループの連続した項目がするので、それは、GROUPBY前にソートのラウンドを必要とします。 –

関連する問題