2011-04-14 51 views
3

我想清理类​​型的字典列表,按以下规则:从类型的字典列表近乎重复的值删除类型的字典 - Python的

1)类型的字典的列表已经排序,因此早期字典是优选的。
2)在较低的字符中,如果['name']['code']字符串值与列表上的任何字典的相同键值相匹配,并且这两个字符之间的int(['cost'])的差值的绝对值是< 2;那么该字典被认为是早期字典的副本,并从列表中删除。

以下是类型的字典列表中选择一个字典:

{ 
'name':"ItemName", 
'code':"AAHFGW4S", 
'from':"NDLS", 
'to':"BCT", 
'cost':str(29.95) 
} 

什么是删除这样的重复的最佳方式?

回答

3

可能有这样做的更pythonic的方法,但是这是基本的伪代码:

def is_duplicate(a,b): 
    if a['name'] == b['name'] and a['cost'] == b['cost'] and abs(int(a['cost']-b['cost'])) < 2: 
    return True 
    return False 

newlist = [] 
for a in oldlist: 
    isdupe = False 
    for b in newlist: 
    if is_duplicate(a,b): 
     isdupe = True 
     break 
    if not isdupe: 
    newlist.append(a) 
+0

虽然有更好的技术方法(尤其是Jochen的答案,它使用'yield'来减少大型列表中的内存使用量),但我更喜欢您的方法的可读性。 – Pranab 2011-04-17 20:59:23

0

样的一个令人费解的问题,但我认为像这样的工作:

for i, d in enumerate(dictList): 
    # iterate through the list of dicts, starting with the first 
    for k,v in d.iteritems(): 
     # for each key-value pair in this dict... 
     for d2 in dictList[i:]: 
      # check against all of the other dicts "beneath" it 
      # eg, 
      # if d['name'] == d2['name'] and d['code'] == d2['code']: 
      #  --check the cost stuff here-- 
+0

谢谢丹尼尔。是的,剪掉这个列表也是我第一个本能的想法,但是我认为Yasser使用两个列表的想法在一年后重新访问代码时最终会变得更加清晰。你怎么看? – Pranab 2011-04-15 08:28:17

3

由于你说的成本是你可以使用的整数:

def neardup(items): 
    forbidden = set() 
    for elem in items: 
     key = elem['name'], elem['code'], int(elem['cost']) 
     if key not in forbidden: 
      yield elem 
      for diff in (-1,0,1): # add all keys invalidated by this 
       key = elem['name'], elem['code'], int(elem['cost'])-diff 
       forbidden.add(key) 

这是一个不那么棘手的方式,r eally计算差异:

from collections import defaultdict 
def neardup2(items): 
    # this is a mapping `(name, code) -> [cost1, cost2, ... ]` 
    forbidden = defaultdict(list) 
    for elem in items: 
     key = elem['name'], elem['code'] 
     curcost = float(elem['cost']) 
     # a item is new if we never saw the key before 
     if (key not in forbidden or 
       # or if all the known costs differ by more than 2 
       all(abs(cost-curcost) >= 2 for cost in forbidden[key])): 
      yield elem 
      forbidden[key].append(curcost) 

这两种解决方案都避免重新扫描每个项目的整个列表。毕竟,如果(name, code)是平等的,成本才会变得有趣,因此您可以使用字典快速查找所有候选项。

+0

感谢您向我介绍'yield'和'set()'。你的答案在技术上总是很棒! – Pranab 2011-04-15 08:30:39