【问题标题】:Min-max python v3 implementation最小值-最大值 python v3 实现
【发布时间】:2014-08-11 18:05:25
【问题描述】:

我目前正在尝试为 python 中的内置 min-max 函数编写等效代码,我的代码返回了一个我完全不理解的非常奇怪的异常:

TypeError: 'generator' object is not subscriptable, min, 7, , 9

当我尝试使用时:

min(abs(i) for i in range(-10, 10))

这是我的代码:

def min(*args, **kwargs):
key = kwargs.get("key", None)
argv=0
for i in args:
    argv+=1
    if argv == 1 and (type(args) is list or type(args) is tuple or type(args) is str):
        min=args[0][0]
        for i in args[0]:
            if key != None:
                if key(i) < key(min):
                    min = i
            else:
                if i < min:
                    min = i
        return min
    else:
        min=args[0]
        for i in args:
            if key != None:
                if key(i) < key(min):
                    min = i
            else:
                if i < min:
                    min = i
        return min

根据文档,我应该能够迭代生成器...

【问题讨论】:

  • 您可以迭代生成器。你不能这样做generator[0](“不可下标”)。它抱怨min=args[0][0]
  • 但是如果我不能在它的值中选择它,我该如何将默认值设置为 min 呢?
  • 首先将其设置为None,然后在迭代生成器时检查它是否为None(因此您可以将其设置为第一个元素),然后(如果没有元素)。
  • 请注意,args始终是一个元组,因此您的 if 块将始终被输入,而您的 else 块将永远不会被输入.此外,由于ifelse 在它们内部都有一个无条件的return,所以你的第一个for 循环永远不会超过第一次迭代。您也可以删除它,并检查argv
  • 好的,谢谢,我不知道,我会尝试 hlt 解决方案并更改我的代码,

标签: python max min minmax


【解决方案1】:

这是我的实现:

def max(*args, **kwargs):
    key = kwargs.get("key", lambda x: x)
    if len(args) == 1:
        args = args[0]
    maxi = None
    for i in args:
        if maxi == None or key(i) > key(maxi):
            maxi = i
    return maxi

def min(*args, **kwargs):
    key = kwargs.get("key", lambda x: x)
    if len(args) == 1:
        args = args[0]
    mini = None
    for i in args:
        if mini == None or key(i) < key(mini):
            mini = i
    return mini

比预览帖更简洁一点。

【讨论】:

    【解决方案2】:

    您遇到的问题是由于min 有两个函数签名。从它的文档字符串中:

    min(...)
        min(iterable[, key=func]) -> value
        min(a, b, c, ...[, key=func]) -> value
    

    因此,它将接受单个位置参数(一个可迭代的,您需要比较谁的值)或几个位置参数,这些参数本身就是值。我认为您需要在函数开始时测试您所处的模式。只需执行args = args[0] 即可将单参数版本转换为多参数版本非常容易。

    这是我实现该功能的尝试。 key 是一个仅限关键字的参数,因为它出现在 *args 之后。

    def min(*args, key=None):    # args is a tuple of the positional arguments initially
        if len(args) == 1:       # if there's just one, assume it's an iterable of values
            args = args[0]       # replace args with the iterable
    
        it = iter(args)          # get an iterator
    
        try:
            min_val = next(it)   # take the first value from the iterator
        except StopIteration:
            raise ValueError("min() called with no values")
    
        if key is None:       # separate loops for key=None and otherwise, for efficiency
            for val in it:    # loop on the iterator, which has already yielded one value
                if val < min_val
                    min_val = val
        else:
            min_keyval = key(min_val)    # initialize the minimum keyval
            for val in it:
                keyval = key(val)
                if keyval < min_keyval:  # compare keyvals, rather than regular values
                    min_val = val
                    min_keyval = keyval
    
        return min_val
    

    这里有一些测试:

    >>> min([4, 5, 3, 2])
    2
    >>> min([1, 4, 5, 3, 2])
    1
    >>> min(4, 5, 3, 2)
    2
    >>> min(4, 5, 3, 2, 1)
    1
    >>> min(4, 5, 3, 2, key=lambda x: -x)
    5
    >>> min(4, -5, 3, -2, key=abs)
    -2
    >>> min(abs(i) for i in range(-10, 10))
    0
    

    【讨论】:

    • 这是一种非常优雅的方式,我必须承认我不会这样想。但我不明白你为什么用 iter(args) 创建一个迭代器... args 已经是一个迭代器了,不是吗?
    【解决方案3】:

    所讨论的函数有很多共同点。事实上,唯一的区别是比较(&lt; vs &gt;)。鉴于这一事实,我们可以实现查找和元素的通用函数,它将使用作为参数传递的比较函数。最小值和最大值示例可能如下所示:

    def lessThan(val1, val2):
      return val1 < val2
    
    def greaterThan(val1, val2):
      return val1 > val2
    
    
    def find(cmp, *args, **kwargs):
      if len(args) < 1:
        return None
    
      key = kwargs.get("key", lambda x: x)
      arguments = list(args[0]) if len(args) == 1 else args
      result = arguments[0]
    
      for val in arguments:
        if cmp(key(val), key(result)):
          result = val
    
      return result
    
    
    min = lambda *args, **kwargs: find(lessThan, *args, **kwargs)
    max = lambda *args, **kwargs: find(greaterThan, *args, **kwargs)
    

    一些测试:

    >>> min(3, 2)
    2
    >>> max(3, 2)
    3
    >>> max([1, 2, 0, 3, 4])
    4
    >>> min("hello")
    'e'
    >>> max(2.2, 5.6, 5.9, key=int)
    5.6
    >>> min([[1, 2], [3, 4], [9, 0]], key=lambda x: x[1])
    [9, 0]
    >>> min((9,))
    9
    >>> max(range(6))
    5
    >>> min(abs(i) for i in range(-10, 10))
    0
    >>> max([1, 2, 3], [5, 6], [7], [0, 0, 0, 1])
    [7]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-19
      • 2019-01-09
      • 1970-01-01
      • 2015-07-04
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多