如何在列表中删除重复的字典,忽略一个字典键?

4
我有一个字典列表。每个字典都有多个键值对,以及一个任意但重要的键值对。例如:
thelist = [
    {"key" : "value1", "k2" : "va1", "ignore_key" : "arb1"}, 
    {"key" : "value2", "k2" : "va2", "ignore_key" : "arb11"},
    {"key" : "value2", "k2" : "va2", "ignore_key" : "arb113"}
]

我希望能够删除重复的字典,只有非“ignore-key”值被忽略。我在Stack Overflow上看到了一个相关问题,但它只考虑完全相同的字典。是否有一种方法可以删除几乎相同的字典,使得上面的数据变为:
thelist = [
    {"key" : "value1", "k2" : "va1", "ignore_key" : "arb1"}, 
    {"key" : "value2", "k2" : "va2", "ignore_key" : "arb11"}
]

无论忽略哪个重复项都没有关系。我该怎么做?

你的值是否始终可哈希化? - DSM
感谢您的回复。抱歉 - 示例情况不够清晰。有多个键值对,只有一个键需要忽略。 - user4467853
@DSM 是的,这些值始终是可哈希的(文本和日期时间对象)。 - user4467853
@user4467853,我假设它们是分组的,或者你如何决定保留哪个? - Padraic Cunningham
有些过度了,但你可以这样做:no_ignore = a_dict.copy(), del no_ignore ["ignore_key"]。然后应用Ami的添加过滤配方,同时在过滤no_ignore时添加a_dict。 - JL Peyret
每个字典中是否有相同的键,不同的键是否可以具有相同的值? - Padraic Cunningham
7个回答

5

保留 key 中已经出现过的值,并删除具有相同值的任何字典:

st = set()

for d in thelist[:]:
    vals = d["key"],d["k2"]
    if vals in st:
        thelist.remove(d)
    st.add(vals)
print(thelist)

[{'k2': 'va1', 'ignore_key': 'arb1', 'key': 'value1'},
{'k2': 'va2', 'ignore_key': 'arb11', 'key': 'value2'}]

如果值总是被分组的,你可以使用key中的value来分组并获取每个组的第一个字典:

from itertools import groupby
from operator import itemgetter
thelist[:] = [next(v) for _, v in groupby(thelist,itemgetter("key","k2"))]
print(thelist)]

print(thelist)
[{'key': 'value1', 'k2': 'va1', 'ignore_key': 'arb1'}, 
{'key': 'value2', 'k2': 'va2', 'ignore_key': 'arb11'}]

或者使用类似 DSM 答案中的生成器来修改原始列表而不进行复制:

def filt(l):
    st = set()
    for d in l:
        vals = d["key"],d["k2"]
        if vals not in st:
            yield d
        st.add(vals)


thelist[:] = filt(thelist)

print(thelist)

 [{'k2': 'va1', 'ignore_key': 'arb1', 'key': 'value1'}, 
{'k2': 'va2', 'ignore_key': 'arb11', 'key': 'value2'}]

如果您不关心删除哪个副本,只需使用reversed即可:
st = set()

for d in reversed(thelist):
    vals = d["key"],d["k2"]
    if vals in st:
        thelist.remove(d)
    st.add(vals)
print(thelist)

使用groupby忽略除ignore_key以外的所有内容:

from itertools import groupby

thelist[:] = [next(v) for _, v in groupby(thelist, lambda d: 
                [val for k, val in d.items() if k != "ignore_key"])]
print(thelist)
[{'key': 'value1', 'k2': 'va1', 'ignore_key': 'arb1'},
 {'key': 'value2', 'k2': 'va2', 'ignore_key': 'arb11'}]

3

你可以把东西塞进一两行里,但我认为编写一个函数更加清晰:

def f(seq, ignore_keys):
    seen = set()
    for elem in seq:
        index = frozenset((k,v) for k,v in elem.items() if k not in ignore_keys)
        if index not in seen:
            yield elem
            seen.add(index)

这提供了

>>> list(f(thelist, ["ignore_key"]))
[{'ignore_key': 'arb1', 'k2': 'va1', 'key': 'value1'}, 
 {'ignore_key': 'arb11', 'k2': 'va2', 'key': 'value2'}]

这里假设你的数值是可哈希的。(如果不是,同样的代码可以使用 seen = []seen.append(index),但对于长列表而言性能会很差。)

1

从您的原始列表开始:

thelist = [
    {"key" : "value1", "ignore_key" : "arb1"}, 
    {"key" : "value2", "ignore_key" : "arb11"},
    {"key" : "value2", "ignore_key" : "arb113"}
]

创建一个集合,并在筛选列表时填充它。
uniques, theNewList = set(), []
for d in theList:]
    cur = d["key"] # Avoid multiple lookups of the same thing
    if cur not in uniques:
        theNewList.append(d)
    uniques.add(cur)

最终,重命名列表:
theList = theNewList

0

你可以使用字典的字典,而不是使用字典列表。每个字典的键值将成为主字典上的键。

像这样:

thedict = {}

thedict["value1"] = {"ignore_key" : "arb1", ...}  
thedict["value2"] = {"ignore_key" : "arb11", ...}

由于字典不允许重复的键,所以您的问题将不存在。


0

不改变thelist

result = []
seen = set()
thelist = [
    {"key" : "value1", "ignore_key" : "arb1"},
    {"key" : "value2", "ignore_key" : "arb11"},
    {"key" : "value2", "ignore_key" : "arb113"}
]

for item in thelist:
    if item['key'] not in seen:
        result.append(item)
        seen.add(item['key'])

print(result)

0
创建一组唯一值,并检查(和更新)它们:
values = {d['key'] for d in thelist}
newlist = []

for d in thelist:
    if d['key'] in values:
        newlist.append(d)
        values -= {d['key']}

thelist = newlist

0

您可以通过使用字典而不是集合来删除重复项,将已接受的答案适应于链接的问题。

以下首先构建一个临时字典,其键是thelist中每个字典中项目的元组,除了被忽略的那个,它保存为与这些键关联的值。这样做可以消除重复项,因为它们将成为相同的键,但保留被忽略的键及其被忽略的值(最后或仅看到的值)。

第二步通过从临时字典中的项目中组合每个键及其关联值来创建由字典组成的thelist

如果您愿意,您可以将这两个步骤合并为完全无法阅读的一行代码...

thelist = [
    {"key" : "value1", "k2" : "va1", "ignore_key" : "arb1"},
    {"key" : "value2", "k2" : "va2", "ignore_key" : "arb11"},
    {"key" : "value2", "k2" : "va2", "ignore_key" : "arb113"}
]

IGNORED = "ignore_key"
temp = dict((tuple(item for item in d.items() if item[0] != IGNORED),
             (IGNORED, d.get(IGNORED))) for d in thelist)
thelist = [dict(key + (value,)) for key, value in temp.iteritems()]

for item in thelist:
    print item

输出:

{'ignore_key': 'arb1', 'k2': 'va1', 'key': 'value1'}
{'ignore_key': 'arb113', 'k2': 'va2', 'key': 'value2'}

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