【问题标题】:Get the n-smallest values from a nested python list从嵌套的 python 列表中获取 n 最小值
【发布时间】:2021-01-15 04:55:36
【问题描述】:

我有以下列表:

l = [(('01001', '01003'), 4.15),
 (('01001', '01005'), 2.83),
 (('01001', '01007'), 3.32),
 (('01001', '01008'), 2.32),
 (('01001', '01009'), 9.32),
 (('01001', '01007'), 0.32),
 (('01002', '01009'), 6.83),
 (('01002', '01011'), 2.53),
 (('01002', '01009'), 6.83),
 (('01002', '01011'), 2.53),
 (('01002', '01009'), 6.83),
 (('01002', '01011'), 2.53),
 (('01003', '01013'), 20.50),
 (('01003', '01013'), 10.50),
 (('01003', '01013'), 0.50),
 (('01003', '01013'), 2.50),
 (('01003', '01013'), 20.30),
 (('01003', '01013'), 12.50),
 (('01003', '01013'), 1.50),
 (('01003', '01013'), 2.40)]

我想为此列表的第一个元素(“01001”、“01002”和“01003”)选择 n 个最小值。

我可以用这段代码计算最小值:

from itertools import groupby
from statistics import mean

{k:min(v for *_, v in v) for k,v in groupby(result_map, lambda x: x[0][0])}

但想得到 3 个最小值和要打印的第二列:

预期结果会是这样的字典:

{'01001': ['01007', '01008', '01005'], '01002': ['01011', '01009', '01013']  , '01003': ['01013', '01013', ''01013']}

任何帮助将不胜感激!

【问题讨论】:

  • 是什么决定了哪些数字会出现在['01007', '01008', '01005'] 等列表中?
  • 你的元组值在某些情况下也会重复 btw,('0100', '01007') 出现多次,如果这样的元组有两个值低于其他第二列值怎么办

标签: python list nested


【解决方案1】:
{k:[e[0][1] for e in sorted(v, key = lambda x: x[1])][:n] for k,v in groupby(result_map, lambda x: x[0][0])}

以上是您提供的带有 groupby 的代码,但稍作修改以计算 n 最小列表而不是 min。

从您的问题示例中,不清楚您是否想要在 n 最小列表中重复元素(第二个条目 '01002': ['01011', '01009', '01013'] 没有重复,但第三个 '01003': ['01013', '01013', ''01013'] 在您的示例中有重复),所以我提供第二个单线解决任务,无需重复:

{k:[e[0][1] for e in sorted({f[0][1] : f for f in v}.values(), key = lambda x: x[1])][:n] for k,v in groupby(result_map, lambda x: x[0][0])}

完整版代码can be found and tried online here!

【讨论】:

  • 必须喜欢单行完全不可读的答案。他们肯定会推广良好的做法......
  • @gold_cy 原始提问者的代码也是单行代码 :),因此我决定使用相同样式的代码(单行代码)进行一些改进。
  • 这不提供 OP 的预期结果。他们似乎想排除重复值,因此“01002”的列表将是 ['01011', '01009', '01013'] 而不是 ['01011', '01011', '01011']。
  • @Stuart 其实提问者的例子是有争议的,第二个元素没有重复元素,但第三个('01003': ['01013', '01013', ''01013'])有重复,所以我不知道他是否要重复。
  • @Stuart 刚刚在我的答案中添加了第二条不重复的单行,以便提问者可以选择他想要的。
【解决方案2】:

以下应该有效:

d={i:sorted([k[0][1] for k in l if k[0][0]==i])[:3] for i in set([i[0][0] for i in l])}

print(d)

{'01001': ['01003', '01005', '01007'], '01002': ['01009', '01009', '01009'], '01003': ['01013', '01013', '01013']}

【讨论】:

  • 必须喜欢单行完全不可读的答案。他们肯定会推广良好的做法......
  • 不符合 OP 的预期结果。不清楚,但他们似乎想按每个元组中的第三个数字排序。
  • OP 的结果不准确,因为 01002 的 01013 实际上并不存在。此外,它与 01003 具有相似的值,这意味着我们不是在寻找唯一值
【解决方案3】:

一个非常明确但直截了当的版本。我只在输入列表lst上迭代一次:

from bisect import bisect_left
from collections import defaultdict

lst = [(('01001', '01003'), 4.15),
       ...
       (('01003', '01013'), 2.40)]

maxlen = 3

ret = defaultdict(list)
val = defaultdict(list)
for ((first, second), value) in lst:
    r = ret[first]
    v = val[first]
    if not r:
        r.append(second)
        v.append(value)
    else:
        if value not in v:
            idx = bisect_left(v, value)
            r.insert(idx, second)
            v.insert(idx, value)
    if len(r) > maxlen:
        ret[first] = r[:3]
        val[first] = v[:3]

print(ret)  # defaultdict(<class 'list'>, {
#  '01001': ['01007', '01008', '01005'], 
#  '01002': ['01011', '01009'], 
#  '01003': ['01013', '01013', '01013']})

print(val)  # defaultdict(<class 'list'>, {
#  '01001': [0.32, 2.32, 2.83], 
#  '01002': [2.53, 6.83], 
#  '01003': [0.5, 1.5, 2.4]})

我使用defaultdictval 存储与结果res 对应的值。

我使用bisect 模块查找插入索引idx。

如果值和结果位于相同的数据结构中并且不在ret 和val 中分开(例如元组甚至命名元组),则设计可能会更好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 2015-04-26
    • 2022-10-12
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    相关资源
    最近更新 更多