3

我有一个按特定键排序的字典列表。每个字典包含 32 个元素,列表中有超过 4000 个字典。我需要代码来处理列表并返回一个删除所有重复项的新列表。

这些链接中的方法:

不要帮助我,因为字典是不可散列的。

有什么想法吗?如果您需要更多信息,请发表评论,我会添加信息。

编辑

重复字典将是具有相同值的任何两个字典list[dictionary][key]


好的,这里有详细的解释给需要的人。

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

[ {
    "ID" : "0001",
    "Organization" : "SolarUSA",
    "Matchcode" : "SolarUSA, Something Street, Somewhere State, Whatev Zip",
    "Owner" : "Timothy Black",
   }, {
    "ID" : "0002",
    "Organization" : "SolarUSA",
    "Matchcode" : "SolarUSA, Something Street, Somewhere State, Whatev Zip",
    "Owner" : "Johen Wilheim",
   }, {
    "ID" : "0003",
    "Organization" : "Zapotec",
    "Matchcode" : "Zapotec, Something Street, Somewhere State, Whatev Zip",
    "Owner" : "Simeon Yurrigan",
   } ]

在这个列表中,第一个和第二个字典是重复的,因为它们Matchcodes是相同的。

现在这个列表按以下代码排序:

# sort_by is "Matchcode"
def sort( list_to_be_sorted, sort_by ):
    return sorted(list_to_be_sorted, key=lambda k: k[sort_by])

所以我有一个整齐的字典列表,按Matchcode. 现在我只需要遍历列表,list[dictionary][key]当两个键值匹配时访问并删除重复项。

4

8 回答 8

11

就像您可以使用 atuple来获得与 a 等效的哈希一样list,您也可以使用 afrozenset来获得与 a 等效的哈希dict。唯一的技巧是您需要传递d.items()而不是传递d给构造函数。

>>> d = {'a': 1, 'b': 2}
>>> s = frozenset(d.items())
>>> hash(s)
-7588994739874264648
>>> dict(s) == d
True

然后您可以使用您最喜欢的您已经看过的解决方案。如果您需要保留订单等,请将它们转储到 aset中,或者使用 aOrderedSetunique_everseen配方等。例如:

>>> unique_sets = set(frozenset(d.items()) for d in list_of_dicts)
>>> unique_dicts = [dict(s) for s in unique_sets]

或者,保留顺序并使用键值:

>>> sets = (frozenset(d.items()) for d in list_of_dicts)
>>> unique_sets = unique_everseen(sets, key=operator.itemgetter(key))
>>> unique_dicts = [dict(s) for s in unique_sets]

当然,如果你有嵌套的列表或字典,你将不得不递归转换,就像你对列表的列表一样。

于 2013-08-28T21:06:22.193 回答
6

用于itertools.groupby()按键值对字典进行分组,然后从每个组中取出第一项。

import itertools

data =[ {
    "ID" : "0001",
    "Organization" : "SolarUSA",
    "Matchcode" : "SolarUSA, Something Street, Somewhere State, Whatev Zip",
    "Owner" : "Timothy Black",
   }, {
    "ID" : "0002",
    "Organization" : "SolarUSA",
    "Matchcode" : "SolarUSA, Something Street, Somewhere State, Whatev Zip",
    "Owner" : "Johen Wilheim",
   }, {
    "ID" : "0003",
    "Organization" : "Zapotec",
    "Matchcode" : "Zapotec, Something Street, Somewhere State, Whatev Zip",
    "Owner" : "Simeon Yurrigan",
   } ]


print [g.next() for k,g in itertools.groupby(data, lambda x: x['Matchcode'])]

给出结果

[{'Owner': 'Timothy Black',  
  'Organization': 'SolarUSA', 
  'ID': '0001',  
  'Matchcode': 'SolarUSA, Something Street, Somewhere State, Whatev Zip'},

 {'Owner': 'Simeon Yurrigan', 
  'Organization': 'Zapotec', 
  'ID': '0003', 
  'Matchcode':'Zapotec, Something Street, Somewhere State, Whatev Zip'}]

我相信这就是你要找的。

编辑:我更喜欢 unique_justseen 解决方案。它更短,更具描述性。

于 2013-11-01T16:30:00.750 回答
4

这个答案对于现在已经消除歧义的问题是不正确的。


于 2013-08-28T20:57:45.497 回答
1

所以我有一个按 Matchcode 排序的字典列表。现在我只需要遍历列表,访问 list[dictionary][key] 并在两个键值匹配时删除重复项。

我仍然不完全确定这意味着什么。听起来您是在说它们将始终按您要用于唯一化的相同键进行排序。如果是这样,您可以unique_justseenitertools食谱中使用,使用您在 中使用的相同键功能sort,例如itemgetter(key).

使用您编辑的问题中的示例list_of_dicts

>>> list(unique_justseen(list_of_dicts, key=itemgetter('Matchcode')))
[{'ID': '0001',
  'Matchcode': 'SolarUSA, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'SolarUSA',
  'Owner': 'Timothy Black'},
 {'ID': '0003',
  'Matchcode': 'Zapotec, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'Zapotec',
  'Owner': 'Simeon Yurrigan'}]

如果它们按与我们唯一化的键不同的键进行排序,那么它们被排序的事实根本不相关,并且unique_justseen不起作用:

>>> list_of_dicts.sort(key=itemgetter('Owner'))
>>> list(unique_justseen(list_of_dicts, key=itemgetter('Matchcode')))
[{'ID': '0002',
  'Matchcode': 'SolarUSA, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'SolarUSA',
  'Owner': 'Johen Wilheim'},
 {'ID': '0003',
  'Matchcode': 'Zapotec, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'Zapotec',
  'Owner': 'Simeon Yurrigan'},
 {'ID': '0001',
  'Matchcode': 'SolarUSA, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'SolarUSA',
  'Owner': 'Timothy Black'}]

但是你只需要使用unique_everseen配方:

>>> list_of_dicts.sort(key=itemgetter('Owner'))
>>> list(unique_everseen(list_of_dicts, key=itemgetter('Matchcode')))
[{'ID': '0002',
  'Matchcode': 'SolarUSA, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'SolarUSA',
  'Owner': 'Johen Wilheim'},
 {'ID': '0003',
  'Matchcode': 'Zapotec, Something Street, Somewhere State, Whatev Zip',
  'Organization': 'Zapotec',
  'Owner': 'Simeon Yurrigan'}]

(当然这次我们得到的是 0002 而不是 0001,因为在排序之后,Owner它现在是它的第一个值Matchcode而不是第二个。)


字典不可散列的事实在这里无关紧要,因为配方只是将 key 函数的结果存储在它们的集合中,所以只要存储在 key 处的值key是可散列的,一切都很好。

于 2013-08-28T21:53:13.137 回答
1

现在我们可以看到,如果特定键匹配,则两个字典是重复的,问题就很简单了。只需遍历字典;跟踪您看到的键,最后从唯一的键中创建一个新列表。

import collections
def get_unique_items(list_of_dicts, key="Matchcode"):
    # Count how many times each key occurs.
    key_count = collections.defaultdict(lambda: 0)
    for d in list_of_dicts:
        key_count[d[key]] += 1

    # Now return a list of only those dicts with a unique key.
    return [d for d in list_of_dicts if key_count[d[key]] == 1]

请注意,我在defaultdict这里使用 a 来计算每个键的出现次数(还有其他方法可以做到这一点,但我个人认为这是最干净的)。我没有使用 aset来跟踪“已访问”键的原因是您将获得列表中每个键的副本,包括重复的键。这意味着您必须保留一秒钟 set,以跟踪真正重复的键(遇到它们时已经在“已访问”键中的键),因此您不包括它们。

另一方面,如果您想要的只是使用每个给定键获取您看到的第一本字典,无论以后是否存在重复,那么一种set方法可以正常工作,就像Mike Graham 的第二个答案一样。

于 2013-08-28T22:27:03.770 回答
0
seen_values = set()
without_duplicates = []
for d in list_of_dicts:
    value = d[key]
    if value not in seen_values:
        without_duplicates.append(d)
        seen_values.add(value)
于 2013-08-28T21:39:39.283 回答
0

基本上你需要类似no_dup(checked_val_extrator, list)no_dup 的东西:

def no_dup(extractor, lst):
   "keeps only first elements encountered for any particular extracted value using =="
   known = set()
   res = []
   for item in lst:
     if extractor(item) in known: continue
     known.add(extractor(item))
     res.append(item)
   return res
于 2014-01-10T23:22:59.187 回答
-1

我不是 100% 清楚你想要达到的目标,但是:

删除所有重复的字典条目

只要你不介意合并所有的字典,

import itertools
dict(itertools.chain(*map(lambda x: x.items(), list_of_dictionaries)))
于 2013-08-28T21:05:29.447 回答