将 JSON 列表简化为唯一的字典项

0 投票
3 回答
2645 浏览
提问于 2025-04-17 09:56

我刚接触Python(也可以用PHP),在网上找了很多资料和问题讨论,但还是有点搞不懂。

我有一个JSON数据,想弄明白怎么从一个包含字典的列表中,创建一个只包含唯一字典的列表,也就是说不想要重复的字典。

举个例子,下面是我测试用的列表:

[{"pStart1a": {"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
"instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
"pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
"pSearch1a":  
{"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""},
 {"pStart1a":{"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
 "instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
 "pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
 "pSearch1a":
 {"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""}]

我想得到一个只包含唯一字典的列表,这样就不会有重复的字典了。

[
  {"pStart1a": 
  {"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
   "instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
   pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
  "pSearch1a":
  {"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
  {"pStart1":""}]

我在考虑遍历最初的列表,把每个字典复制到一个新列表里,然后进行简单的比较,如果新列表里没有这个字典,就把它加进去。请问有没有其他更好的方法呢?

谢谢!

3 个回答

-1

如果我理解你的问题没错的话,你可以试试这个:

import json
from pprint import pprint

json_string = """[{"pStart1a": {"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
"instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
"pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
"pSearch1a":
{"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""},
 {"pStart1a":{"termVal":"1122","termMenu":"CLASS_SRCH_WRK2_STRM","instVal":"OSUSI",
 "instMenu":"CLASS_SRCH_WRK2_INSTITUTION","goBtn":"CLASS_SRCH_WRK2_SSR_PB_SRCH",
 "pagechk":"CLASS_SRCH_WRK2_SSR_PB_SRCH","nPage":"CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH"},
 "pSearch1a":
 {"chk":"CLASS_SRCH_WRK2_MON","srchbtn":"DERIVED_CLSRCH_SSR_EXPAND_COLLAPS"}},
 {"pStart1":""}]
"""

result = {}
for dct in json.loads(json_string):
    for key, value in dct.iteritems():
        result[key] = value

pprint(result)

输出结果:

 {u'pSearch1a': {u'chk': u'CLASS_SRCH_WRK2_MON',
                u'srchbtn': u'DERIVED_CLSRCH_SSR_EXPAND_COLLAPS'},
 u'pStart1': '',
 u'pStart1a': {u'goBtn': u'CLASS_SRCH_WRK2_SSR_PB_SRCH',
               u'instMenu': u'CLASS_SRCH_WRK2_INSTITUTION',
               u'instVal': u'OSUSI',
               u'nPage': u'CLASS_SRCH_WRK2_SSR_PB_CLASS_SRCH',
               u'pagechk': u'CLASS_SRCH_WRK2_SSR_PB_SRCH',
               u'termMenu': u'CLASS_SRCH_WRK2_STRM',
               u'termVal': u'1122'}}

编辑

注意,这个方法会把你的字典列表转换成一个字典。这样可能会更方便你进行后续的操作。

你也可以把 result 转换成列表:

list_result = [{key:value} for key, value in result.iteritems()]

注意 2

比较是基于字典的键,并且它会把嵌套的值提取到最外层。我不确定这对提问者来说是否可行。可能你不应该使用这个方法。不过无论如何,在这组数据上,它的速度比用 repr() 来比较字典快了8倍。

0

最简单的方法是用 list(set(your_list_of_dicts)),但这样做不行,因为Python中的字典是可变的,不能被哈希(也就是说,它们没有实现 __hash__)。这是因为Python无法保证在你把字典放进 setdict 后,字典的哈希值不会改变。

不过在你的情况下,既然你似乎没有修改数据,你可以自己计算一个哈希值,然后用这个哈希值和字典结合起来,比较容易地找到唯一的JSON对象,而不需要对每个字典进行全面的递归比较。

首先,我们需要一个函数来计算字典的哈希值。与其自己编写哈希函数,不如使用Python内置的 hashlib 中的一个:

def dict_hash(d):
    out = hashlib.md5()
    for key, value in d.iteritems():
        out.update(unicode(key))
        out.update(unicode(value))
    return out.hexdigest()

(注意,这依赖于 unicode(...) 对你每个值返回唯一的东西——如果你的字典中有自定义类,而这些类的 __unicode__ 返回类似 "MyClass instance" 的内容,这样就会失败,或者需要修改。此外,在你的例子中,字典是扁平的,但我留给读者一个练习,如何扩展这个解决方案,以便处理包含其他字典或列表的字典。)

由于 dict_hash 返回的是一个字符串,而字符串是不可变的,所以你现在可以用一个字典来找到唯一的元素:

uniques_map = {}
for d in list_of_dicts:
    uniques[dict_hash(d)] = d
unique_dicts = uniques_map.values()
3

如果oldlist是一个包含字典的列表(比如说,通过json.loads(jsonstring)得到的结果),那么可以用下面的方式来构建一个新的列表:

encountered = set()
newlist = []
for i in oldlist:
    repr_i = repr(i)
    if repr_i in encountered:
       continue
    encountered.add(repr_i)
    newlist.append(i)

print newlist

你也可以用其他的函数来替代repr,比如说用repr的哈希摘要。

撰写回答