【问题标题】:simplifying a json list to the unique dict items将 json 列表简化为唯一的 dict 项
【发布时间】:2012-01-10 18:15:10
【问题描述】:

python 新手(也可以使用 php).. 搜索了各种站点/SO.. 仍然有一个心理障碍。

得到一个 json,并试图弄清楚如何获取一个包含 dicts 的列表并创建一个具有唯一 dicts 集的结果列表..

例如,下面是测试列表:

[{"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":""}]

我正在考虑遍历初始列表,将每个 dict 复制到一个新列表中,并进行基本比较,如果下一个 dict 不在新列表中,则添加它。还有其他/更好的方法吗?

谢谢

【问题讨论】:

  • 你不使用 Python 的内置 json 库有什么原因吗?
  • 是实际问题吗?您将如何处理结果列表?也许您可以使用不同的格式或对数据进行一些简化?

标签: python json list dictionary unique


【解决方案1】:

如果 oldlist 包含 Python 中的 dicts 列表(例如,作为 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的哈希摘要。

【讨论】:

  • 您可以通过将repr(i) 的结果存储在变量中来提高效率。
  • 就目前而言,这并不能保证有效:如果两个项目具有相同的哈希值,则可以根据项目在字典中输入的顺序生成不同的repr。跨度>
  • 我同意这一点。需要一些特殊的递归函数来遍历嵌套的字典/列表,字典的排序键。
  • 作为 python >= 2.7 的一种可能的解决方法,您可以使用 json.loadsobject_pairs_hook 参数设置为 OrderedDict(),然后使用 json.dumps 而不是 repr 来比较字典。但这完全是矫枉过正:)
【解决方案2】:

最简单的方法 -- 使用 list(set(your_list_of_dicts)) 不起作用,因为 Python 字典是可变的且不可散列的(也就是说,它们没有实现 __hash__)。这是因为 Python 无法保证将字典的哈希值插入到 setdict 后不会改变。

但是,在您的情况下,由于您(似乎没有)修改数据,您可以计算自己的哈希值,并将其与字典一起使用,以便相对轻松地找到唯一的 JSON 对象,而无需对每个字典与其他字典进行完全递归比较。

首先,我们需要一个函数来计算字典的哈希值。与其尝试构建我们自己的哈希函数,不如使用来自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()

【讨论】:

  • hi dcrosta...试图实现/测试/学习您发布的内容..“独特”的定义是列表/字典?我会假设它不是一个列表,因为“dict_hash”的输出是一个字符串......谢谢
  • uniques 是一个字典,是的——但是在字典上调用 .values() 会给你一个字典中的值(不是键)列表。因为我们将原始字典 d 存储为每个键的值(其中键是哈希),所以 .values() 为您提供具有唯一哈希的字典列表(即原始 list_of_dicts 中的唯一字典)
【解决方案3】:

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

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

比较基于字典键,并将嵌套值提取到根级别。不知道 OP 是否可以访问。您可能不应该使用此解决方案。无论如何,它比使用 repr() 比较字典快 8 倍(在此数据上)。

【讨论】:

  • 这个答案是完全错误的。结果应该是 OP 指定的唯一字典列表。
  • @RomanSusi,无论如何,我认为这个解决方案有生命权,因为对 dict 的操作比对 dicts 列表的操作更容易。
  • 操作可能更容易,但我猜你的解决方案不是针对 OP 的问题。
  • @RomanSusi,你是对的。添加了获取要回答的听写列表的方法。
  • 好的。但是,它仍然是错误的:它没有地方说字典只有一个键,并且两个字典仅基于键的相等性而不是值的相等...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-03
  • 2016-08-21
  • 1970-01-01
  • 2015-04-19
  • 2018-10-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多