【问题标题】:Sorting a list of dictionaries by all keys being unique按唯一的所有键对字典列表进行排序
【发布时间】:2017-06-19 09:56:32
【问题描述】:

用这个把我的头发拉出来。

我有一个字典列表,每个唯一条目没有唯一的主 ID 键(字典是动态构建的):

dicts = [{'firstname': 'john', 'lastname': 'doe', 'code': 'crumpets'},
         {'firstname': 'john', 'lastname': 'roe', 'code': 'roe'},
         {'firstname': 'john', 'lastname': 'doe', 'code': 'crumpets'},
         {'firstname': 'thom', 'lastname': 'doe', 'code': 'crumpets'},
]

如何过滤掉这样的字典列表,其中列表中的任何重复 {} 都被删除了?所以我需要检查所有三个字典键是否都与列表中的另一个匹配......然后如果满足该检查,则从dict 中丢弃它。

因此,对于我上面的示例,需要删除第一个和第三个“条目”,因为它们是重复的。

【问题讨论】:

  • 所以从有重复的那一刻起,你想删除所有元素吗?
  • 你能显示你在等待什么吗?
  • 将字典映射到元组对,创建一组(这使得它们独一无二)并将它们映射回字典
  • 否 - 只需删除重复项。因此,如果列表中的一个字典等于另一个 - 删除其中之一(但不能同时删除)。
  • 可能的解决方案,stackoverflow.com/questions/9427163/…

标签: python list sorting dictionary


【解决方案1】:

您使用从 dicts 中创建 freezesets 并将它们放入一个集合中以删除欺骗:

dcts = [dict(d) for d in set(frozenset(d.items()) for d in dcts)]
print(dcts)

[{'code': 'roe', 'firstname': 'john', 'lastname': 'roe'},
 {'code': 'crumpets', 'firstname': 'thom', 'lastname': 'doe'},
 {'code': 'crumpets', 'firstname': 'john', 'lastname': 'doe'}]

如果您选择删除所有重复项,您可以使用计数器:

from collections import Counter

dcts = [dict(d) for d, cnt in Counter(frozenset(d.items()) for d in dcts).items() 
                                                                      if cnt==1]
print(dcts)

[{'code': 'roe', 'firstname': 'john', 'lastname': 'roe'},
 {'code': 'crumpets', 'firstname': 'thom', 'lastname': 'doe'}]

【讨论】:

  • 会看看我是否可以实现这个 - 但不确定我是否理解如何动态定义字典然后交叉检查它。我认为需要实现这一点并做更多的阅读。谢谢。
  • 除了onelining之外还有什么理由不使用简单的for循环和这样的新容器:new_ct = []for item in ct: if item not in new_ct: new_ct.append(item)
  • @MichaelRoberts 他回答的第一部分就是你想要的dcts = [dict(d) for d in set(frozenset(d.items()) for d in dcts)]
  • @SardorbekImomaliev 抱歉,是的,这是正确的。当我意识到时,我正在编辑我的评论。
  • 为了扩展我上面的评论,在分配之前肯定会引用 dcts 吗?
【解决方案2】:

删除不可散列元素列表中的重复项要求您动态将它们设为可散列:

def remove_duplicated_dicts(elements):
    seen = set()
    result = []
    for element in elements:
        element_as_tuple = tuple(element.items())
        if element_as_tuple not in seen:
            seen.add(element_as_tuple)
            result.append(element)
    return result

d = [{'firstname': 'john', 'lastname': 'doe', 'code': "crumpets"},
        {'firstname': 'john', 'lastname': 'roe', 'code': "roe"},
        {'firstname': 'john', 'lastname': 'doe', 'code': "crumpets"},
        {'firstname': 'thom', 'lastname': 'doe', 'code': "crumpets"},
]

print(remove_duplicated_dicts(d))

附言。

与接受的 Moses Koledoye 答案的非明显差异(截至 2017 年 6 月 19 日 13:00:00):

  • 保留原始列表顺序;
  • 更快的转换:dict -> tuple 而不是 dict -> frozendict -> dict(持保留态度:我没有制定基准)。

【讨论】:

  • 非常感谢您的回答 - 尽管我非常感谢您的回答,但我接受了更高投票的回答(我也在使用 Django 的函数中工作,所以我不想嵌套基于 Django 的方法之上的基本字典排序方法)。不过还是谢谢你。
【解决方案3】:

鉴于 字典的值是可散列的,我们可以生成自己的 uniqness 过滤器:

def uniq(iterable, key = lambda x:x):
    keys = set()
    for item in iterable:
        ky = key(item)
        if ky not in keys:
            yield item
            keys.add(ky)

然后我们可以简单地使用过滤器,例如:

list(uniq(dicts,key=lambda x:(x['firstname'],x['lastname'],x['code'])))

过滤器保持原来的顺序,并且将——对于这个例子——生成:

>>> list(uniq(dicts,key=lambda x:(x['firstname'],x['lastname'],x['code'])))
[{'code': 'crumpets', 'firstname': 'john', 'lastname': 'doe'},
 {'code': 'roe', 'firstname': 'john', 'lastname': 'roe'},
 {'code': 'crumpets', 'firstname': 'thom', 'lastname': 'doe'}]

【讨论】:

  • 非常感谢您的回答 - 尽管我非常感谢您的回答,但我接受了更高投票的回答(我也在使用 Django 的函数中工作,所以我不想嵌套基于 Django 的方法之上的基本字典排序方法)。不过还是谢谢你。
猜你喜欢
  • 2014-02-11
  • 2019-12-30
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-22
相关资源
最近更新 更多