我有一个按特定键排序的字典列表。每个字典包含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]
并在两个键值匹配时删除重复项。
答案 0 :(得分:10)
正如您可以使用tuple
获取与list
相当的可清除值,您可以使用frozenset
获取与dict
相当的可清除值。唯一的技巧是你需要将d.items()
而不是d
传递给构造函数。
>>> d = {'a': 1, 'b': 2}
>>> s = frozenset(d.items())
>>> hash(s)
-7588994739874264648
>>> dict(s) == d
True
然后你可以使用你最喜欢的解决方案。如果您需要保留订单等,请将它们转储到set
或使用OrderedSet
或unique_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]
当然,如果你有嵌套的列表或dicts,你必须递归转换,就像你对列表一样。
答案 1 :(得分: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解决方案。它更短,更具描述性。答案 2 :(得分:4)
对于现在消除歧义的问题,这个答案是不正确的。
dicts是否都有相同的密钥?如果是这样,写一个像
这样的函数the_keys = ["foo", "bar"]
def as_values(d):
return tuple(d[k] for k in the_keys)
unique_values = unique_everseen(list_of_dicts, key=as_values)
其中unique_everseen
定义为http://docs.python.org/2/library/itertools.html
如果dicts不一致,请使用更通用的密钥,例如FrozenDict
我发布到https://stackoverflow.com/a/2704866/192839
答案 3 :(得分:1)
所以我有一个整齐的字典列表按Matchcode排序。现在我只需要迭代列表,访问列表[字典] [密钥]并在两个键值匹配时删除重复项。
我还不完全确定这意味着什么。听起来你说它们将始终按照你想要用来统一的相同键进行排序。如果是这样,您可以使用unique_justseen
中使用的sort
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'}]
中使用的相同键功能,例如itertools
recipes。
使用编辑过的问题中的示例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'}]
但是你必须改为使用Owner
食谱:
Matchcode
(当然这次我们有0001而不是0001,因为在key
上排序之后,它现在是{{1}}而不是第二个的第一个值。)
字典不可清除的事实在这里不相关,因为配方只是将键函数的结果存储在它们的集合中,因此只要存储在键{{1}}的值是可清除的,一切都很好。
答案 4 :(得分: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
来计算每个键的出现次数(还有其他方法可以做到这一点,但我认为这是最干净的,个人的)。我没有使用set
跟踪“已访问”密钥的原因是,您将获得列表中每个密钥的一个副本,包括重复密钥。这意味着您必须保留第二个 set
,以跟踪真正重复的密钥(当您遇到密钥时已经存在于“已访问”密钥中的密钥),所以你不要不包括它们。
另一方面,如果您想要的只是获取每个给定密钥所看到的第一个字典,无论是否重复,set
方法都可以正常工作,例如在{{ 3}}
答案 5 :(得分: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)
答案 6 :(得分: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
答案 7 :(得分:-1)
我并不是100%明确你想要实现的目标,但是:
只要您不介意合并所有词典,
import itertools
dict(itertools.chain(*map(lambda x: x.items(), list_of_dictionaries)))