【问题标题】:Python - extract min/max value from list of tuplesPython - 从元组列表中提取最小值/最大值
【发布时间】:2019-04-04 22:00:48
【问题描述】:

我有一个元组列表如下:

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

你好,

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

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 cmets 了解他在下面的帖子。

【问题讨论】:

  • 你试过地图功能吗?
  • 你能发布你的代码来产生你的输出吗?
  • 欢迎来到 StackOverflow。请按照您创建此帐户时的建议阅读并遵循帮助文档中的发布指南。 On topichow to ask... the perfect question 在此处申请。 StackOverflow 不是设计、编码、研究或教程资源。但是,如果您遵循您在网上找到的任何资源,进行诚实的编码尝试并遇到问题,那么您将有一个很好的示例可以发布。
  • 嗨 rickert 和 Prune,我已经修改了我的帖子。我最初的草稿已经包含了这个,但后来认为保持简单和重点可能会更好。我接受你的观点,并将在以后的帖子中这样做。感谢您的反馈。

标签: python list tuples subset


【解决方案1】:

您可以使用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 列表中;您可以在 groupby for 循环中迭代时直接打印最小值和最大值:

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))

【讨论】:

  • 嗨滑块谢谢!这很好用。我稍微修改了代码,以便我可以检索最小值和最大值之间的差异。但是,我尝试将这些结果附加到一个新列表中以进行进一步的工作,并且只有该计算的最后一个结果出现在列表中。我用我尝试过的 2 种方法扩展了我的 OP。
  • @AlexM 您应该在 for 循环之外(之前)声明 test_lst,否则每次循环运行时它都会一直重置为一个空列表(这就是为什么您只看到最后一个计算) .
  • @slider 当然。最近几周我开始关注python,并在阅读您的帖子时回忆起早期的教程之一。我会编辑我的帖子。非常感谢!
【解决方案2】:

另一种方法:

max_list = {}
min_list = {}
for i in data:
    if i[0] not in max_list:
        max_list[i[0]] = -99999
        min_list[i[0]] = 99999

    if max_list[i[0]] < int(i[2]):
        max_list[i[0]] = int(i[2])

    if min_list[i[0]] > int(i[1]):
        min_list[i[0]] = int(i[1])



for ele in max_list:
    print(ele, ' min: ', min_list[ele], 'max: ', max_list[ele])

【讨论】:

  • 嗨@Maria Nazari 感谢您提供替代方法。在 python 中做同样事情的方法有很多!
【解决方案3】:
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')]


result = {}  # construct result dictionary
for i in data:
    cur_min, cur_max = map(int, i[1:])
    min_i, max_i = result.setdefault(i[0], [cur_min, cur_max])
    if cur_min < min_i:
        result[i[0]][0] = cur_min
    if cur_max > max_i:
        result[i[0]][1] = cur_max
# print(result)  # dictionary containing keys with list of min and max values for given key >>> {'A': [2, 117], 'B': [25, 251], 'C': [157, 208], 'D': [166, 183], 'E': [2, 117]}

for k, v in result.items():  # loop to print output
    print("{} min: {} max: {}".format(k, v[0], v[1]))

输出:

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

【讨论】:

    【解决方案4】:

    这是另一种可以使用 Pandas 库的方法:

    import pandas as pd
    
    #The same dataset you provided us
    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')]
    
    #Generate dataframe df
    df = pd.DataFrame(data=data)
    #Convert strings to their respective numerical values
    df[[1,2]] = df[[1,2]].apply(pd.to_numeric, errors='ignore')
    
    #Group values using column 0
    df.groupby(0).agg({1: min, 2: max})
    

    我们使用带有字典作为参数的 agg 方法,以便找到每个分组范围的第 1 列中的最小值和第 2 列中的最大值。

    这给出了以下结果:

         1    2
    0
    A    2  117
    B   25  251
    C  157  208
    D  166  183
    E    2  117
    

    【讨论】:

    • 感谢您的建议。我发现将数据视为表/矩阵/数组/数据框更容易一些。
    • 很高兴我能以某种方式提供帮助!
    猜你喜欢
    • 1970-01-01
    • 2020-05-19
    • 2021-06-20
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 2021-07-30
    • 1970-01-01
    • 2022-11-01
    相关资源
    最近更新 更多