user3002473
user3002473

Reputation: 5074

Fastest way to find the greatest 1st and 2nd items of a list of tuples simultaneously in python

I was fiddling around with lists of tuples and I was wondering, what would be the fastest way to grab the greatest 1st and 2nd values from the list of tuples simultaneously? For example assume we have a list of tuples like so:

_list = [(0, 3), (2, 1), (3, 2), (2, 4)]

The max first value is 3 and the max second value is 4, therefore I would like to get the tuple (3, 4). What might be the fastest way to do this?

Upvotes: 1

Views: 72

Answers (4)

Steinar Lima
Steinar Lima

Reputation: 7821

After timing the various scripts posted here (with list length of 10000), the fastest version is a traditional for loop:

mi = mj = float('-inf')
for i, j in lst:
    if i > mi:
        mi = i
    if j > mj:
        mj = j
print mi, mj

But the prettiest has to be by using zip:

lst = [(0, 3), (2, 1), (3, 2), (2, 4)]
print tuple(max(x) for x in zip(*lst))
# -> (3, 4)

Timings (on Python 2.7.1):

Function        Time    Performance
max_for2(lst):  0.9241  100%
max_izip(lst):  1.3093  141%
max_for1(lst):  1.3596  147%
max_zip(lst):   1.4750  159%
max_gen(lst):   2.1235  229%

Timing code:

setup = '''
from itertools import izip
from random import randint

def max_zip(lst):
    return tuple(max(x) for x in zip(*lst))

def max_izip(lst):
    return tuple(max(x) for x in izip(*lst))

def max_gen(lst):
    return max(a[0] for a in lst), max(a[1] for a in lst)

def max_for1(lst):
    mi = mj = float('-inf')
    for i, j in lst:
        mi = i if i > mi else mi
        mj = j if j > mj else mj

    return mi, mj

def max_for2(lst):
    mi = mj = float('-inf')
    for i, j in lst:
        if i > mi:
            mi = i
        if j > mj:
            mj = j

    return mi, mj

lst = [(randint(0, 10000), randint(0, 10000)) for _ in xrange(10000)]
'''

from timeit import timeit

statements= (
    'max_zip(lst)',
    'max_izip(lst)',
    'max_gen(lst)',
    'max_for1(lst)',
    'max_for2(lst)'
)

timings = {}

for stmt in statements:
    timings[stmt] = timeit(stmt=stmt, setup=setup, number=1000)

print 'Function\t\tTime\tPerformance'
for key, value in sorted(timings.iteritems(), key=lambda x: x[1]):
    print '{}:\t{:.4f}\t{}%'.format(
        key, value, int(100*value/min(timings.values())))

Upvotes: 4

Kei Minagawa
Kei Minagawa

Reputation: 4521

Simply do like this. :)

max(lst)[0], max(lst, key=lambda x:x[1])[1]

Time:

>>> %timeit max(lst)[0],max(lst, key=lambda x:x[1])[1]
1000000 loops, best of 3: 1.32 us per loop

    #http://stackoverflow.com/a/23023689/2931409
>>> %timeit (max(a[0] for a in lst), max(a[1] for a in lst))
1000000 loops, best of 3: 1.41 us per loop

    #http://stackoverflow.com/a/23023736/2931409
>>> %timeit tuple(max(x) for x in itertools.izip(*lst))
1000000 loops, best of 3: 1.73 us per loop

Upvotes: 0

Octopus
Octopus

Reputation: 8325

This would do the trick:

(max(a[0] for a in list), max(a[1] for a in list))

Upvotes: 1

A.J. Uppal
A.J. Uppal

Reputation: 19264

>>> mx = []
>>> mn = []
>>> for i, j in _list:
...     mx.append(i)
...     mn.append(j)
...
>>> x = (max(mx), max(mn))
>>> x
(3, 4)

Append each value to a list, and then get the maximum. From that, create a tuple.

Upvotes: 1

Related Questions