2016-02-12 59 views
2

非常像filter工作,我希望能夠從一個序列中刪除重複的項目,但根據回調的返回值。根據回調刪除重複

set不允許。

my_list = [{'foo': 330}, {'foo': 560}, {'foo': 320}] 

# What I would like: 
remove_duplicate(my_list, lambda val: int(val['foo']/100)) 

# Would return 
[{'foo': 330}, {'foo': 560}] 
# or 
[{'foo': 560}, {'foo': 320}] 

我實際上並不關心訂單或要保留的訂單,我認爲所有這些數據都是重複的。

理想情況下,我正在尋找一種內置方式來執行此操作。

回答

2

嗯,事實證明,沒有內置的方式來做到這一點。

有一個很好的黑客:

使用的事實,dict絕不能有兩次相同的密鑰,你可以這樣做:

list({callback(val): val for val in my_list}.values()) 

# In your case: 
list({int(val['foo']/100): val for val in my_list}.values()) 

# Returns: 
[{'foo': 320}, {'foo': 560}] 

如果你關心的秩序,文檔提出以下配方unique_everseen

def unique_everseen(iterable, key=None): 
    "List unique elements, preserving order. Remember all elements ever seen." 
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D 
    # unique_everseen('ABBCcAD', str.lower) --> A B C D 
    seen = set() 
    seen_add = seen.add 
    if key is None: 
     for element in ifilterfalse(seen.__contains__, iterable): 
      seen_add(element) 
      yield element 
    else: 
     for element in iterable: 
      k = key(element) 
      if k not in seen: 
       seen_add(k) 
       yield element 

哪個更優雅,但是,可悲(IMO),不是內置的。

1

您可以使用過濾功能。不幸的是,不支持lambda表達式,因爲它們不支持賦值。相反,您可以定義一個函數來檢查val ['foo']/100是否已經在您看到的一組項目中。如果沒有,保留它。否則,不要。

my_list = [{'foo': 330}, {'foo': 560}, {'foo': 320}] 
kept_set = set() 
def cut_fun(x): 
    remove_ind = int(x['foo']/100) 
    if remove_ind in kept_set: 
     return 0 
    kept_set.add(remove_ind) 
    return 1 


print filter(cut_fun, my_list)