【问题标题】:Reduce by key in python在python中按键减少
【发布时间】:2015-07-08 02:47:52
【问题描述】:

我正在尝试在 python 中考虑最有效的方法。

假设我有一个元组列表:

[('dog',12,2), ('cat',15,1), ('dog',11,1), ('cat',15,2), ('dog',10,3), ('cat',16,3)]

假设我有一个函数,它接受其中两个元组并将它们组合起来:

def my_reduce(obj1, obj2):
    return (obj1[0],max(obj1[1],obj2[1]),min(obj1[2],obj2[2]))

我如何通过'key'执行有效的reduce,这里的key可能是第一个值,所以最终结果会是这样的:

[('dog',12,1), ('cat',16,1)]

【问题讨论】:

  • 你是说min(obj1[2],obj2[2])
  • 很好,谢谢!我把它固定在上面
  • 这看起来很适合熊猫
  • 嘿@mgoldwasser,2 年太晚了,但这是另一种方式:stackoverflow.com/a/48343896/5858851。顺便说一句,我你认为我是的前同事。

标签: python reduce


【解决方案1】:

或者,如果您安装了 pandas

import pandas as pd

l = [('dog',12,2), ('cat',15,1), ('dog',11,1), ('cat',15,2), ('dog',10,3), ('cat',16,3)]

pd.DataFrame(data=l, columns=['animal', 'm', 'n']).groupby('animal').agg({'m':'max', 'n':'min'})
Out[6]: 
         m  n
animal       
cat     16  1
dog     12  1

获取原始格式:

zip(df.index, *df.values.T) # df is the result above
Out[14]: [('cat', 16, 1), ('dog', 12, 1)]

【讨论】:

  • 我同意 :) ... 愚蠢的 wim 和他的 0 宽度空格:P
【解决方案2】:

我不认为reduce 是完成这项工作的好工具,因为您必须首先使用 itertools 或类似工具按键对列表进行分组。否则,您将比较 catsdogs,一切都会崩溃!

只是一个简单的循环就可以了:

>>> my_list = [('dog',12,2), ('cat',15,1), ('dog',11,1), ('cat',15,2)]
>>> output = {}
>>> for animal, high, low in my_list:
...     try:
...         prev_high, prev_low = output[animal]
...     except KeyError:
...         output[animal] = high, low
...     else:
...         output[animal] = max(prev_high, high), min(prev_low, low)

那么如果你想恢复原来的格式:

>>> output = [(k,) + v for k, v in output.items()]
>>> output
[('dog', 12, 1), ('cat', 15, 1)]

请注意,这将破坏原始列表中的排序。如果要保留键首次出现的顺序,请改为使用 OrderedDict 初始化输出。

【讨论】:

    【解决方案3】:

    如果你想使用你的my_reducereduce,你可以这样做。实际上,它相当短:

    准备工作:

    from itertools import groupby
    from operator import itemgetter
    
    pets = [('dog',12,2), ('cat',15,1), ('dog',11,1), ('cat',15,2), ('dog',10,3), ('cat',16,3)]
    
    def my_reduce(obj1, obj2):
        return (obj1[0],max(obj1[1],obj2[1]),min(obj1[2],obj2[2]))
    

    解决方案:

    print [reduce(my_reduce, group)
           for _, group in groupby(sorted(pets), key=itemgetter(0))]
    

    输出:

    [('cat', 16, 1), ('dog', 12, 1)]
    

    【讨论】:

    • 我可以知道您在 print 语句中使用的语法/速记是什么吗?它似乎是一个函数调用,然后是 for 循环,并且由 for 循环定义的变量在函数调用中传递。 reduce(my_reduce, group) for _, groupby(sorted(pets), key=itemgetter(0))
    • @Lee 这是一个“列表理解”。
    【解决方案4】:

    如果你真的想使用 reduce,我认为这是可行的(它会给你一个 dict 返回而不是一个列表,但是嗯)

    def my_reduce(obj1, obj2):
        if not isinstance(obj1,dict):
            return reduce(my_reduce,[{},obj1,obj2])
        try:
            obj1[obj2[0]] = max(obj1[obj2[0]][0],obj2[1]),min(obj1[obj2[0]][1],obj2[2])
        except KeyError:
            obj1[obj2[0]] = obj2[1:]
        return obj1
    
    my_list = [('dog',12,2), ('cat',15,1), ('dog',11,1), ('cat',15,2), ('dog',10,3), ('cat',16,3)]
    print reduce(my_reduce,my_list)
    

    我认为其他两种解决方案都更好

    【讨论】:

    • 不,因为这会将所有内容折叠为一个元素,但我希望每个键一个元素
    猜你喜欢
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 2015-08-27
    • 2018-02-20
    • 1970-01-01
    • 1970-01-01
    • 2022-06-26
    • 1970-01-01
    相关资源
    最近更新 更多