2011-01-25 81 views
1

我有一個包含一千個項目的Python字典。每個項目本身就是一本字典。我正在尋找一種乾淨優雅的方式來解析每個項目,並找到&創建模板。Python詞典,找到相似之處

這裏的個人字典結構的簡化示例:

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

由此,我想穿過一次,並且如果,的1000共享相同的高度和寬度500,確定的是,如此我可以從該數據構建模板,並將模板ID分配給「模板」。我可以創建一個巨大的引用散列,但我希望有一個更清晰更優雅的方法來實現這一點。

實際數據包括更接近30個鍵,其中一小部分子集需要從模板檢查中排除。

回答

0

@eumiro有一個優秀的核心理念,即使用itertools.groupby()安排在一起分批與共同價值觀的項目。然而,除了忽略用@Jochen Ritzel指出的同樣的關鍵函數(並且在文檔中也提到過)來排序之外,他也沒有提到你提到的其他幾件事。

下面是一個更完整和更長的答案。它決定了模板,並將它們分成一個段落,認爲是字典。爲此,首先創建一個排序的項目列表後,它使用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 2011-01-26 03:16:07

3

鑑於類型的字典items的字典:

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只會組連續的項目。 – 2011-01-25 19:12:50