从“for in”循环中获取最小值和最大值

3

这是我的第一篇帖子,也许我不该来这里,但是还是试试吧...

如何从“for in”循环的输出中找到最大值和最小值?

我尝试了min()和max()函数,但出现以下错误...

TypeError: 'int' object is not iterable

这是我的代码...

import urllib2
import json

def printResults(data):
  # Use the json module to load the string data into a dictionary
  theJSON = json.loads(data)

  # test bed for accessing the data
  for i in theJSON["features"]:
   t = i["properties"]["time"]
   print t

def main():
  # define a variable to hold the source URL
  urlData = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson"

  # Open the URL and read the data
  webUrl = urllib2.urlopen(urlData)
  #print webUrl.getcode()
  if (webUrl.getcode() == 200):
    data = webUrl.read()
    # print out our customized results
    printResults(data)
  else:
    print "Received an error from server, cannot retrieve results " +  str(webUrl.getcode())

if __name__ == "__main__":
   main()

任何指针都将不胜感激!

3
请 [编辑] 您的帖子并包含完整的错误文本。它会告诉您问题的确切位置。 - MattDMo
3个回答

2

您可以在可迭代对象上使用minmax。由于您正在循环遍历theJSON["features"],因此可以使用以下代码:

print min(e["properties"]["time"] for e in theJSON["features"])
print max(e["properties"]["time"] for e in theJSON["features"])

你也可以将结果存储在一个变量中,以便稍后使用:

my_min = min(...)
my_max = max(...)

正如 @Sabyasachi 所评论的,你也可以使用以下方法:

print min(theJSON["features"], key = lambda x:x["properties"]["time"])

请注意,每个迭代器都会再次迭代列表,因此特别是因为您已经自己迭代了它,您可以手动跟踪最小值和最大值,并保存两个额外的迭代。 - poke
你可以通过使用 min(theJSON['features'],key=lambda x:x["properties"]["time"]) 来避免额外的 generator expression,从而节省时间和空间。 - Guy
@poke 和 sabyaschi:OP 没有提到性能是一个问题,所以清晰度应该是最大的关注点。如果性能是最高优先级,那么 OP 可能不会使用 Python。 - Steven Rumbalski
这个代码可以运行,但是它每次都会打印出值。我该如何只传递一次到一个变量中,以便稍后使用?然后我想从最大值中减去最小值,得到一个“开始时间值”。 - zedzero
@zedzero 记住这段代码将在循环外部。你可以使用我在答案中提到的变量赋值:some_variable = min(...) - Christian Tapia

1
这是一个手动跟踪最小值和最大值的示例。
minVal = 0
maxVal = 0
for i in yourJsonThingy:
    if i < minVal:
        minVal = i
    if i > maxVal:
        maxVal = i

你不能这样做:

for i in yourJsonThingy:
    maxVal = max(i)

因为i只是一个整数,没有最大值。
但是你可以对一组整数执行这些操作。
maxVal = max(yourJsonThingy)
minVal = min(yourJsonThingy)

1
在只需要遍历一次可迭代对象的情况下(比如说这是一个昂贵的操作,这也是唯一应该这样做而不是分别调用maxmin的原因,但是下面的方法在性能上比分别调用更好,见下面的数字):
def max_min(iterable, key=None):
    ''' 
    returns a tuple of the max, min of iterable, optional function key 
    tuple items are None if iterable is of length 0
    '''
    it = iter(iterable)
    _max = _min = next(it, None)
    if key is None:
        for i in it:
            if i > _max:
                _max = i
            elif i < _min:
                _min = i
    else:
        _max_key = _min_key = key(_max)
        for i in it:
            key_i = key(i)
            if key_i > _max_key:
                _max, _max_key = i, key_i
            elif key_i < _min_key:
                _min, _min_key = i, key_i
    return _max, _min

使用方法:

>>> max_min(range(100))
(99, 0)
>>> max_min(range(100), key=lambda x: -x)
(0, 99)

进行性能检查:
>>> timeit.timeit('max(range(1000)), min(range(1000))', setup=setup)
70.95577674100059
>>> timeit.timeit('max_min(range(1000))', setup=setup)
65.00369232000958

这相当于在不使用lambda的情况下分别调用内置函数maxmin,性能提升了约9%。使用lambda:
>>> timeit.timeit('max(range(1000), key=lambda x: -x),min(range(1000), key=lambda x: -x)', setup=setup)
294.17539755300095
>>> timeit.timeit('max_min(range(1000), key=lambda x: -x)', setup=setup)
208.95339999899443

这比使用lambda分别调用每个操作要提高40%以上。

这个测试有点缺陷,当单独调用min/max时,不应该两次创建range()。此外,在展示性能提升时,您需要使用原始未优化的速度作为除数,因此您的性能提升实际上只有不到30%,而不是40%。 - Lie Ryan
创建两个可迭代对象是这段代码的重点,我们可能无法或不想将整个数据集都实例化到内存中。30%的减少大约等同于40%的增加,但还是感谢您指出这一点。 - Russia Must Remove Putin
不,两次创建范围并不是重点,这是有缺陷的方法论,就是这样。真正应该传递给timeit设置阶段的是创建原始可迭代对象,否则你测量的不是max+min与max_min的速度,而是对range的两次调用与一次调用。我无法复制您的结果,在任何情况下,max_min都不会比两次调用max和min更快。 - Lie Ryan
另外,30%和40%之间存在33%的差异((40%-30%)/ 30%= 33%),这不是可以忽略的差异。 - Lie Ryan
以对数思考。 - Russia Must Remove Putin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接