135

I have a list with ~10^6 tuples in it like this:

[(101, 153), (255, 827), (361, 961), ...]
  ^     ^
  X     Y

I want to find the maximum value of the Ys in this list, but also want to know the X that it is bound to.

How do I do this?

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Berk Özbalcı
  • 3,016
  • 3
  • 21
  • 27

3 Answers3

233

operator.itemgetter():

In [53]: lis=[(101, 153), (255, 827), (361, 961)]

In [81]: from operator import itemgetter

In [82]: max(lis, key=itemgetter(1))  # Faster solution
Out[82]: (361, 961)

In [83]: max(lis, key=itemgetter(1))[0]  # Faster solution
Out[83]: 361

lambda:

In [54]: max(lis, key=lambda item: item[1])
Out[54]: (361, 961)

In [55]: max(lis, key=lambda item: item[1])[0]
Out[55]: 361

timeit comparison of operator.itemgetter vs lambda:

In [84]: %timeit max(lis, key=itemgetter(1))
1000 loops, best of 3: 232 us per loop

In [85]: %timeit max(lis, key=lambda item: item[1])
1000 loops, best of 3: 556 us per loop
Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 8
    (+1) would `operator.itemgetter(1)` would work better than the lambda in this case because the lambda would get created for each of the 10**6 times. – inspectorG4dget Oct 30 '12 at 18:40
  • @AshwiniChaudhary: is there a considerable speed difference between `operator.itemgetter` and `lambda` in such cases, though? – inspectorG4dget Oct 30 '12 at 18:47
  • 1
    @inspectorG4dget, `itemgetter` is about twice as fast according to a quick test I did. However, it doesn't have anything to do with creating the function multiple times as you say in your first comment. A predefined pure python function that does the same thing as `lambda x: x[1]` performs at the same speed. I assume that `itemgetter` does some of its work at c speed. – senderle Oct 30 '12 at 19:10
  • @senderle That's strange, [my timings](http://pastebin.com/u80nNYg0) show that `lambda` is in 17% faster than `itemgetter` in this case. Why did we get so different results? – Lauritz V. Thaulow Oct 30 '12 at 19:17
  • 1
    @lazyr i think you should use `max(lis,key=itemgetter(1))`, not `max(lis,itemgetter(1)) ` ` – Ashwini Chaudhary Oct 30 '12 at 19:21
  • 1
    +1, but two minor nits: I'd put the `itemgetter` solution first instead of second (it's more Pythonic, simpler, and faster…), and I'd use a different variable name instead of `x` (since the OP is referring to his tuples as `(x, y)`, so it could be potentially confusing to call the whole thing `x`). – abarnert Oct 30 '12 at 19:35
  • @Ashwini Chaudhary How to use timeit in standard python file? – YasserKhalil Mar 20 '22 at 05:17
11

In addition to max, you can also sort:

>>> lis
[(101, 153), (255, 827), (361, 961)]
>>> sorted(lis,key=lambda x: x[1], reverse=True)[0]
(361, 961)
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
1

You could loop through the list and keep the tuple in a variable and then you can see both values from the same variable...

num=(0, 0)
for item in tuplelist:
  if item[1]>num[1]:
    num=item #num has the whole tuple with the highest y value and its x value
CoffeeRain
  • 4,460
  • 4
  • 31
  • 50
  • I think `max()` is a lot easier. – Burhan Khalid Oct 30 '12 at 18:31
  • @BurhanKhalid Yeah, but that was posted while I was writing my post. I wasn't thinking about that. I'll edit it to not say that anymore, but keep my post just so there is an alternative way to do it for posterity. :) – CoffeeRain Oct 30 '12 at 18:32
  • what if all the tuples contain negative values? num stays (0,0) – Davos Nov 22 '18 at 00:07
  • @Davos can use something like LOWEST_VALUE instead of 0 which stores the lowest value your program is gonna use – komikat May 31 '22 at 12:04