从一个字典列表中删除重复项,当其中一个键值不同时

4

我看到了一些类似的答案,但我找不到适用于这种情况的具体内容:

我有一个像这样的字典列表:

[
 {"element":Bla, "version":2, "date":"12/04/12"},
 {"element":Bla, "version":2, "date":"12/05/12"},
 {"element":Bla, "version":3, "date":"12/04/12"}
]

实际上字典中还有很多其他键,但我想要做的是删除所有具有完全相同的键值对(日期除外)的条目。也就是说,删除所有重复项(实际上并非完全重复,因为只有日期不同)。在这种情况下,我期望得到的结果是:
[
 {"element":Bla, "version":2, "date":"12/04/12"},
 {"element":Bla, "version":3, "date":"12/04/12"}
]

谢谢你们提供的所有答案,我有点卡住了。不过还有一个问题,如果日期是日期时间对象,你会如何只保留最新的日期? - user443850
1
如果您不需要按照初始列表中的顺序使用字典,您可以使用几乎相同的算法来完成,但是您将使用result={}代替result=[],其中包含对h: d的配对,并且如果缺少h或新的d具有更新的日期,则需要更新result。在这里,您不需要seen,因为它的作用将由result扮演。尽管您将失去顺序。如果您需要顺序,您将需要进行两次通行证。第一次收集最新日期,第二次构建有序列表。 - ovgolovin
我使用了相同的解决方案,但在运行重复查找程序之前只是对列表进行了排序。 - user443850
5个回答

6

您说您在字典中有很多其他未在问题中提到的键。

这里有一个O(n)算法来完成您需要的操作:

>>> seen = set()
>>> result = []
>>> for d in dicts:
...     h = d.copy()
...     h.pop('date')
...     h = tuple(h.items())
...     if h not in seen:
...         result.append(d)
...         seen.add(h)

>>> pprint(result)
[{'date': '12/04/12', 'element': 'Bla', 'version': 2},
 {'date': '12/04/12', 'element': 'Bla', 'version': 3}]

h是字典的一个副本,使用pop方法将其中的date键删除。

然后创建一个元组作为可哈希类型,并将其添加到set中。

如果之前从未出现过h,则将其附加到result并添加到seen中。对seen的添加操作是O(1),查找操作也是如此(h not in seen)。

最后,result仅包含在定义的h值方面是唯一的元素。


我猜你应该对 h.items() 进行排序。 - thkang
@user443850,初始字典中除了字符串之外,还有其他的数据吗? - ovgolovin
@user443850,“Bla”是一个对象吗? - ovgolovin
是的,整数和日期时间对象。不过,将seen设置为列表也可以。还有元组和其他类型。 - user443850
@drewk 是的!从评论中我看不出哪个是不可哈希的(int、string、datetime都是可哈希的)。 - ovgolovin
显示剩余14条评论

3
你可以使用 itertools 中的 "recipe" 来创建一个新的 list,其中不含重复元素。
list(unique_everseen(original_list, key=lambda e: '{element}@{version}'.format(**e)))

如果您的“key”需要比我编写的lambda更宽(以容纳更多的值),那么将其提取到一个函数中可能是值得的。
def key_without_date(element):
    return '@'.join(["{}".format(v) for k,v in element.iteritems() if k != 'date'])

list(unique_everseen(original_list, key=key_without_date))

1

对于糟糕的变量命名表示歉意。可能有更简洁的方法,但这应该可以工作。

seen = {(item["element"], item["version"]): False for item in mylist}

output = []
for item in mylist:
    item_key = (item["element"], item["version"])
    if not seen[item_key]:
        output.append(item)
        seen[item_key] = True

1
Pandas可以快速解决这个问题:
import pandas as pd
Bla = "Bla"
d = [
{"element":Bla, "version":2, "date":"12/04/12"},
{"element":Bla, "version":2, "date":"12/05/12"},
{"element":Bla, "version":3, "date":"12/04/12"}
]
df = pd.DataFrame(d)
df[~df.drop("date", axis=1).duplicated()]

输出:

       date element  version
0  12/04/12     Bla        2
2  12/04/12     Bla        3

0

这个可以运行:

LoD=[
{"element":'Bla', "version":2, 'list':[1,2,3], "date":"12/04/12"},
{"element":'Bla', "version":2, 'list':[1,2,3], "date":"12/05/12"},
{"element":'Bla', "version":3, 'list':[1,2,3], "date":"12/04/12"}
]

LoDcopy=[]
seen=set()


for d in LoD:
    dc=d.copy()
    del dc['date']
    s=dc.__str__()
    if s in seen: continue
    seen.add(s)
    LoDcopy.append(d)    

print LoDcopy 

打印:

[{'date': '12/04/12', 'version': 2, 'list': [1, 2, 3], 'element': 'Bla'}, 
 {'date': '12/04/12', 'version': 3, 'list': [1, 2, 3], 'element': 'Bla'}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接