【问题标题】:Python function to find the min/max based on single attribute from a nested dictionary structurePython函数根据嵌套字典结构中的单个属性查找最小值/最大值
【发布时间】:2018-02-27 12:46:45
【问题描述】:

以下数据表示:

[
 {u'0xbd4f1cc0da707c5712651b659b86766ec6f25af5e388fc82474523339dd1da37': u'90000'},
 {u'0x05a04a7bb2500087c14bc89eb6a49cd4c5afcac63270aff2d4508e610f606eed': u'40000'},
 {u'0xc3f68d46b9e462110e4897a41b573a10fef72747fd4c9e8413eb2e4cba0af9b5': u'21000'},
 {u'0x79dcc6ab82b2024a0d4135d4fa3a5cd62ab740f28fffa3fc4dfdb8b00430baab': u'158971'},
 {u'0x034c9e7f28f136188ebb2a2630c26183b3df90c387490159b411cf7326764341': u'21000'},
 {u'0xffda7269775dcd710565c5e0289a2254c195e006f34cafc80c4a3c89f479606e': u'1000000'},
 {u'0x90ca439b7daa648fafee829d145adefa1dc17c064f43db77f573da873b641f19': u'90000'},
 {u'0x7cba9f140ab0b3ec360e0a55c06f75b51c83b2e97662736523c26259a730007f': u'40000'},
 {u'0x92dedff7dab405220c473aefd12e2e41d260d2dff7816c26005f78d92254aba2': u'21000'},
 {u'0x0abe75e40a954d4d355e25e4498f3580e7d029769897d4187c323080a0be0fdd': u'21000'},
 {u'0x22c2b6490900b21d67ca56066e127fa57c0af973b5d166ca1a4bf52fcb6cf81c': u'90000'},
 {u'0x8570106b0385caf729a17593326db1afe0d75e3f8c6daef25cd4a0499a873a6f': u'90000'},
 {u'0x8adfe7fc3cf0eb34bb56c59fa3dc4fdd3ec3f3514c0100fef800f065219b7707': u'40000'},
 {u'0x8b0fe2b7727664a14406e7377732caed94315b026b37577e2d9d258253067553': u'21000'},
 {u'0x244b29b60c696f4ab07c36342344fe6116890f8056b4abc9f734f7a197c93341': u'50000'},
 {u'0xf2b5b8fb173e371cbb427625b0339f6023f8b4ec3701b7a5c691fa9cef9daf63': u'121000'},
 {u'0xf8f2a397b0f7bb1ff212b6bcc57e4a56ce3e27eb9f5839fef3e193c0252fab26': u'121000'}
]

从这个循环中生成:

dict_hash_gas = list()
for line in inpt:
    resource = json.loads(line)
    dict_hash_gas.append({resource['first']:resource['second']})

根据看起来或多或少的数据,如下所示:

{"first":"A","second":"1","third":"2"} 
{"first":"B","second":"1","third":"2"} 
{"first":"C","second":"2","third":"2"} 
{"first":"D","second":"3","third":"2"} 
{"first":"E","second":"3","third":"2"} 
{"first":"F","second":"3","third":"2"} 

我试图找到每个字典中第二个值的最大值,即

{"first":"A","second":"LOOKING_FOR_MAX"}

如何从该嵌套字典集中访问所有第二个值(看起来像 u'90000' 的值),记录并输出 maxmin


精确定义术语:在上面的示例中,即:

{u'0xbd4f1cc0da707c5712651b659b86766ec6f25af5e388fc82474523339dd1da37': u'90000'},
{u'0x05a04a7bb2500087c14bc89eb6a49cd4c5afcac63270aff2d4508e610f606eed': u'40000'},
{u'0xc3f68d46b9e462110e4897a41b573a10fef72747fd4c9e8413eb2e4cba0af9b5': u'21000'},

我想根据u'90000'u'40000'u'21000' 进行搜索——这就是我所说的“第二”值。

我想选择max 将仅基于数字,所以在这种情况下u'90000'


编辑:

尝试通过以下方式调用它,我生成了以下重现的错误:

def _main():

    with open('transactions000000000029.json', 'rb') as inpt:
        dict_hash_gas = list()
        for line in inpt:
            resource = json.loads(line)
            dict_hash_gas.append({resource['hash']:resource['gas']})

    pairs = list(_as_pairs(dict_hash_gas))
    if pairs:
        # Avoid a ValueError from min() and max() if the list is empty.
        print(min(pairs, key=lambda pair: pair.value))
        print(max(pairs, key=lambda pair: pair.value))

【问题讨论】:

  • 你尝试过什么,到底有什么问题?
  • 您知道如何在单个dict 中访问'second' 值吗?你知道如何遍历列表中的项目吗?这看起来很简单......
  • 在这个`{u'0xbd4f1cc0da707c5712651b659b86766ec6f25af5e388fc82474523339dd1da37': u'90000'}, the second would be u'90000', so I'd like to search on the basis of 00
  • @KevinJ.Chase 所以我只是试了一下,但我收到了这个错误pprint.pprint(sorted_x = sorted(dict_hash_gas.items(), key=operator.itemgetter(1))) AttributeError: 'list' object has no attribute 'items'
  • 肯定需要数值,那是错误

标签: python dictionary nested max min


【解决方案1】:

一旦您的数据以易于处理的形式出现,它就是单行的。 在这种情况下,由于这些字典显然是某种记录,理想的数据类型是自定义类或 collections.namedtuple。 我选择了namedtuple,因为所有值都是原子的且不可变的。 (此外,它还带有许多方便的功能,例如不错的__str____hash__ 方法,而且效率更高。)

下面的所有工作都在_as_pairs 中,它从令人沮丧的单项字典列表中生成不可变的键值对。 它还转换字符串化的整数 (value) 到你希望的 actual 整数中。 之后,使用数据就很容易了。

import collections

# FIXME:  Use more descriptive names than "Pair", "key", and "value".
Pair = collections.namedtuple('Pair', ['key', 'value'])

def _as_pairs(pairs):
    for pair in pairs:
        # TODO:  Verify the dict conatains exactly one item?
        for k, v in pair.items():
            # Should the `key` string also be an integer?
            #yield Pair(key=int(k, base=16), value=int(v))
            yield Pair(key=k, value=int(v))

def _main():
    # Abbreviated below, but conatains same inputs as your example.
    dict_hash_gas = [
      ...,
      {u'0xffda...606e': u'1000000'},
      {u'0x90ca...1f19': u'90000'},
      ...,
      ]
    pairs = list(_as_pairs(dict_hash_gas))
    if pairs:
        # Avoid a ValueError from min() and max() if the list is empty.
        print(min(pairs, key=lambda pair: pair.value))
        print(max(pairs, key=lambda pair: pair.value))

if '__main__' == __name__:
    _main()

输出(Python 3):

Pair(key='0xc3f6...f9b5', value=21000)
Pair(key='0xffda...606e', value=1000000)

我在 cmets 中包含了一些建议:

  • 这些字典每个都只有一个条目重要吗?

  • 那些十六进制字符串应该 (我称之为id) 也可以转成整数?

我不知道你在用这个做什么,所以我不能回答这两个问题。

【讨论】:

  • cool- 我绝对认为这是正确的方法。我发布了对 OP 的更新,其中包含我最近一次尝试的遗憾结果 - 但是当我早上醒来时,我会再试一次 :)
  • @s.matthew.english:你是如何定义Pair的?您是否更改了字段名称?关键字参数必须与字段名称匹配。
  • 是的,这就是我的想法——所以我尝试将Pair(key=k, value=int(v)) 的每个实例都更改为Pair(hash=k, gas=int(v)),这是正确的方法吗?这是我根据我尝试运行它时收到的错误消息的猜测,即TypeError: __new__() got an unexpected keyword argument 'key',正在python docs 中寻找有关它的一些信息,但到目前为止还没有找到解决方案。我描述的那个替换结果是这样的print(min(pairs, hash=lambda pair: pair.gas)) TypeError: min() got an unexpected keyword argument
  • @s.matthew.english:假设您已将字段命名为 'hash''gas',是的。请参阅“Basic Example”中的第三行(查找注释“使用位置或关键字参数实例化”)。
  • @s.matthew.english:第二个keymin(或max)的参数。它与namedtuple 无关。放慢速度并阅读错误消息...新错误告诉您它来自min(),而不是Pair
【解决方案2】:

您是否受限于在这里使用字典?元组列表可能更易于使用:

dict_hash_gas = list()
for line in inpt:
    resource = json.loads(line)
    dict_hash_gas.append((resource['first'], resource['second']))

sorted_data = sorted(dict_hash_gas, key=lambda x: int(x[1]))
minimum = sorted_data[0]
maximum = sorted_data[-1]

收益: ('0xc3f68d46b9e462110e4897a41b573a10fef72747fd4c9e8413eb2e4cba0af9b5', '21000') 最少 和 ('0xffda7269775dcd710565c5e0289a2254c195e006f34cafc80c4a3c89f479606e', '1000000') 为最大值

使用collections.namedtuple 编辑以显示示例:

from collections import namedtuple

DataItem = namedtuple('DataItem', ['first', 'second'])

dict_hash_gas = list()
for line in inpt:
    resource = json.loads(line)
    dict_hash_gas.append(DataItem(resource['first'], resource['second']))

排序(dict_hash_gas, key=lambda x: int(x.second))

【讨论】:

  • 伙计,我认为我应该坚持使用 dict,因为这只是一个更大的代码库的一部分,它全部基于 dict,我尝试了你建议的 dict,但我得到了错误 AttributeError: 'tuple' object has no attribute 'values'
  • 我同意,2 元素字典列表使这比它必须的要困难得多。 @s.matthew.english:如果您使用collections.namedtuple,您将获得两全其美的优势 --- 轻松的点字段名称访问以及轻松的排序更低的内存使用。跨度>
  • 那会是什么样子?
  • 对于给定的输入,字典的键函数将返回int(item.values()[0])。您还可以显示 max 函数的关键函数使用情况。
  • 我看到使用这样的字典的唯一问题是,除非您使用 Python3.6+(直到 dict 实现再次更改),否则无法保证您想要的值将在任何特定索引处的item.values()。您可能可以使用单独的键函数而不是 lambda,并根据您知道且我们不知道的某些模式找到正确的值。
猜你喜欢
  • 2015-07-18
  • 2020-01-02
  • 1970-01-01
  • 2018-01-08
  • 2015-08-05
  • 2021-03-05
  • 1970-01-01
  • 2019-04-22
  • 1970-01-01
相关资源
最近更新 更多