Min-max python v3实现

时间:2014-08-11 18:05:26

标签: python max min minmax

我目前正在尝试为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

根据文档,我应该可以迭代生成器...

3 个答案:

答案 0 :(得分:1)

您遇到的问题是由于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

答案 1 :(得分: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 :(得分:0)

有问题的功能有很多共同之处。事实上,唯一的区别是比较(< vs >)。鉴于这一事实,我们可以为查找和元素实现泛型函数,它将使用作为参数传递的比较函数。 min和max示例可能如下所示:

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]