首页 > 解决方案 > Python - 从元组列表中提取最小值/最大值

问题描述

我有一个元组列表如下:

data = [
    ('A', '59', '62'), ('A', '2', '6'), ('A', '87', '92'),
    ('A', '98', '104'), ('A', '111', '117'),
    ('B', '66', '71'), ('B', '25', '31'), ('B', '34', '40'), ('B', '46', '53'),
    ('B', '245', '251'), ('B', '235', '239'), ('B', '224', '229'), ('B', '135', '140'),
    ('C', '157', '162'), ('C', '203', '208'),
    ('D', '166', '173'), ('D', '176', '183'),
    ('E', '59', '62'), ('E', '2', '6'), ('E', '87', '92'), ('E', '98', '104'), ('E', '111', '117')
]

它们对应于更大数据集的一个子集,因此我如上所述提取以简化这篇文章。每个元组的第一个元素,即 A、B、C、D、E... 是一个标识符,可以存在多个副本。

我想为每个 ID/类别(A、B、C、D、E ...)提取:

1 - 元组第二个元素的最小值

2 - 元组第三个元素的最大值

最终输出列表应如下所示:

A: min = 2, max = 117
B: min = 25, max = 251
C: min = 157, max = 208
D: min = 166, max = 183
E: min = 2, max = 117

我尝试了一种基于这篇文章的方法:How to remove duplicate from list of tuple when order is important

我通过使用仅包含前 2 个元素的元组并仅提取最小值来简化测试。

输出如下所示:

('A', '111')
('B', '135')
('C', '157')
('D', '166')
('E', '111')

它应该是:

('A', '2')
('B', '25')
('C', '157')
('D', '166')
('E', '2')

我正在寻找一种可以与完整的“三元组”示例一起使用的方法,以避免将数据拆分为多个子集。

非常感谢您的时间。

编辑 1 -2018-10-31

你好,

请在下面查看我的编辑,其中包括之前未包含的代码片段。这在帖子的前一部分中给出了错误的最小值。

data_min_only = [('A', '59'), ('A', '2'), ('A', '87'), ('A', '98'), ('A', '111'), ('B', '66'), ('B', '25'), ('B', '34'), ('B', '46'), ('B', '245'), ('B', '235'), ('B', '224'), ('B', '135'), ('C', '157'), ('C', '203'), ('D', '166'), ('D', '176'), ('E', '59'), ('E', '2'), ('E', '87'), ('E', '98'), ('E', '111')]

from collections import OrderedDict

empty_dict = OrderedDict()

for item in data_min_only:

    # Get old value in dictionary if exist
    old = empty_dict.get(item[0])

    # Skip if new item is larger than old
    if old:
        if item[1] > old[1]:
            continue
        else:
            del d[item[0]]

    # Assign
    empty_dict[item[0]] = item

list(empty_dict.values())

我在想每个类别的元组值的顺序是问题所在(在迭代data_min_only.

感谢所有张贴者的及时回复和建议/解决方案!我目前正在研究这些内容,以尝试理解并进一步调整它们。

编辑 2 -2018-10-31

我调整了@slider 建议以检索最小值和最大值之间的差异。我还尝试将该结果输出到如下列表,但只显示最后一个结果。

for k, g in groupby(sorted(data), key=lambda x: x[0]):
    vals = [(int(t[1]), int(t[2])) for t in g]
    print (max(i[1] for i in vals) - min(i[0] for i in vals))
    test_lst = []
    test_lst.append((max(i[1] for i in vals) - min(i[0] for i in vals)))

我也试过这个,但得到了相同的结果:

for i in vals:
    test_lst2 = []
    test_lst2.append((max(i[1] for i in vals) - min(i[0] for i in vals)))

对于这种循环,将结果提取到列表的最佳方法是什么?

再次感谢。

编辑 3 -2018-10-31

test_lst = []
for k, g in groupby(sorted(data), key=lambda x: x[0]):
    vals = [(int(t[1]), int(t[2])) for t in g]
    print (max(i[1] for i in vals) - min(i[0] for i in vals))
    test_lst.append((max(i[1] for i in vals) - min(i[0] for i in vals)))

提取循环数据的解决方案 - 空列表应该在循环之外。请在下面查看@slider 对他的帖子的评论。

标签: pythonlisttuplessubset

解决方案


您可以itertools.groupby先使用“id”键进行分组,然后计算每个组的最小值和最大值:

from itertools import groupby

groups = []
for k, g in groupby(sorted(data), key=lambda x: x[0]):
    groups.append(list(g))

for g in groups:
    print(g[0][0], 'min:', min(int(i[1]) for i in g), 'max:', max(int(i[2]) for i in g))

输出

A min: 2 max: 117
B min: 25 max: 251
C min: 157 max: 208
D min: 166 max: 183
E min: 2 max: 117

请注意,您不必将组首先存储在groups列表中;您可以在groupbyfor 循环中进行迭代时直接打印最小值和最大值:

for k, g in groupby(sorted(data), key=lambda x: x[0]):
    vals = [(int(t[1]), int(t[2])) for t in g]
    print(k, 'min:', min(i[0] for i in vals), 'max:', max(i[1] for i in vals))

推荐阅读