【问题标题】:Finding the lowest values in an array of dict which also have matching attributes, returning the largest grouping在具有匹配属性的 dict 数组中查找最小值,返回最大的分组
【发布时间】:2019-04-14 03:40:19
【问题描述】:

这很容易通过几个循环来完成,但我确信有一种更有效的方法可以实现这一点,我很想学习。

考虑以下 dict 数组,它表示从 nosql 数据库中提取的数据。

x = [
    {
        "loc" : "alpha",
        "tag" : 1,
        "dist" : 5
    },
    {
        "loc" : "bravo",
        "tag" : 0,
        "dist" : 2
    },
    {
        "loc" : "charlie",
        "tag" : 5,
        "dist" : 50
    },
    {
        "loc" : "delta",
        "tag" : 4,
        "dist" : 2
    },
    {
        "loc" : "echo",
        "tag" : 2,
        "dist" : 30
    },
    {
        "loc" : "foxtrot",
        "tag" : 4,
        "dist" : 2
    },
    {
        "loc" : "gamma",
        "tag" : 4,
        "dist" : 2
    },
    {
        "loc" : "hotel",
        "tag" : 0,
        "dist" : 2
    },
]

我想找到所有具有最低 'dist' 值的项目,如果有多个具有相同最低值的 dict,我希望对具有最多 dicts 的属性 'tag' 进行分组相同的最低值。

例如,从上面返回的所需数据将是:

r = [
    {
        "LocationName" : "delta",
        "tag" : 4,
        "dist" : 2
    },
    {
        "loc" : "foxtrot",
        "tag" : 4,
        "dist" : 2
    },
    {
        "loc" : "gamma",
        "tag" : 4,
        "dist" : 2
    }
]

总结:dist:2 是最小值,[bravo, delta, foxtrot, gamma, hotel] 的 dist 都是 2,[bravo, hotel] 的标签是:0 和 [delta, foxtrot, gamma]有一个标签:4 。 dicts [delta, foxtrot, gamma] 的数组被返回,因为它们有更多具有相同匹配标签和最低 dist。

我正在使用 python 3.6。

感谢您的帮助和关注!

【问题讨论】:

    标签: python arrays python-3.x dictionary


    【解决方案1】:

    您可以为 max()min() 指定一个 key(即 lambda 函数),这有助于解决此问题。对于您的第一次测试,

    lowest_single_dist = min(x, key=lambda i: i["dist"])
    

    返回x 中具有最低"dist" 值的元素。如果您想要所有具有该标签值的元素,您可以使用列表推导:

    lowest_dists = [i for i in x if i["dist"] == lowest_single_dist["dist"]]
    

    为了获得最大的分组,我将首先在该子集中为"tag" 创建一组可能的值,然后检查lowest_dists 中每个值的数量,然后取具有最高计数的值:

    tags = [i["tag"] for i in lowest_dists]              # get a list of just the tags
    ct = {t: tags.count(t) for t in set(tags)}           # make a dict of tag:count for each unique tag
    max_tag = max(ct, key=lambda x: ct[x])               # find the largest count and get the largest tag
    r = [i for i in lowest_dists if i["tag"] == max_tag] # use another list comprehension to get all the max tags
    

    如果您想将其全部缩短为两行,您可以不那么 Python 并这样做:

    m = min(x, key=lambda i: (i["dist"], -1 * max([j["tag"] for j in x if j["dist"] == i["dist"]].count(i["tag"])))
    r = [i for i in x if i["tag"] == m["tag"] and i["dist"] == m["dist"]]
    

    这利用了您可以返回一个元组作为排序键的事实,并且只有第一个相等时才会检查元组的第二个值。我将扩展第一行并解释每个部分的作用:

    m = min(x, key=lambda i: (
        i["dist"], -1 * max(
            [j["tag"] for j in x if j["dist"] == i["dist"]].count(i["tag"])
        ))
    
    • 最里面的列表解析生成x 中所有元素的标签列表,"dist" 的值与i 相同
    • 然后,计算与i相同的标签数量
    • 乘以 -1 使其为负,这样min() 的行为正确
    • 创建一个包含i["dist"] 和我们刚刚计算的值(i["tag"]x 中的频率)的元组,并为每个元素返回它
    • "dist" 的值最低且"tag" 的值最频繁的列表元素分配给m
    • x 中的元素子列表分配给r"dist""tag" 的值相同

    所以与上面的过程基本相同,但更短,效率更低,而且更复杂一些。

    【讨论】:

    • 太棒了,非常感谢 - 我从这个解决方案中学到了很多
    【解决方案2】:

    按字典在'dist'处的值对字典列表进行排序并取最低

    x.sort(key= lambda x:x['dist'])
    lowest = x[0]['dist']
    

    创建一个字典列表,其中 'dist' 的值等于最低值

    x2 = [i for i in x if i['dist']==lowest]
    

    这应该是你的答案。如果列表中有多个项目,请重复上述过程。

    if len(x2)>1:
      x3 = [i['tag'] for i in x2]
      mode = max(set(x3), key=x3.count)
      r = [i for i in x if i['tag']==mode]
    

    【讨论】:

    • 虽然这可能会回答作者的问题,但它缺少一些解释性文字和/或文档链接。如果没有围绕它们的一些短语,原始代码 sn-ps 并不是很有帮助。您可能还会发现how to write a good answer 非常有帮助。请编辑您的答案。
    猜你喜欢
    • 2016-06-30
    • 2021-12-27
    • 2018-10-05
    • 1970-01-01
    • 2021-09-15
    • 2014-05-07
    • 1970-01-01
    • 2022-07-08
    • 1970-01-01
    相关资源
    最近更新 更多