jpcgandre
jpcgandre

Reputation: 1505

Work with list of lists of tuples

I have this list:

dCF3v=[[(1.90689635276794, -44704.76171875)],
       [(1.90689635276794, -44705.76171875)],
       [(1.90689635276794, -44706.76171875)],
       [(1.90689635276794, -44707.76171875)]
      ]

I'd like to compare the second element of each tuple and find the absolute maximum:

-44707.76171875

My code looks like:

CF3=0
for x in dCF3v:
    if abs(x[1])>abs(CF3):
        CF3=x[1]

Upvotes: 2

Views: 302

Answers (6)

Inbar Rose
Inbar Rose

Reputation: 43477

My attempt is to help you get the fastest, and most readable version possible. To do so my suggestion is to first create a generator which will yield the values you want. And then to perform the builtin max() function on this generator. The reason this is faster/more efficient is almost the same as embedding the generator inside the max() function, only using local variables is faster in Python than using global ones, once the max() function does not have to lookup indexes like x[0][1] it is faster.

vals = (abs(x[0][1]) for x in dCF3v)
print max(vals)

Timing:

I timed the difference between mine and mgilsons answer using the following code:

import time
dCF3v = [[(1.90689635276794, -44706.76171875)], [(1.90689635276794, -44706.76171875)], [(1.90689635276794, -44706.76171875)], [(1.90689635276794, -44706.76171875)]]

def method_inbar(l):
    vals = (abs(x[0][1]) for x in l)
    max(vals)

def method_mgilson(l):
    max(abs(x[0][1]) for x in l)

def timer(multiplier=[1,10,100,1000]):
    for m in multiplier:
        print "timing the speed using multiplier: %s" % m
        now = time.time()
        for i in range(100000):
            method_inbar(dCF3v*m)
        print "inbar's method: %r" % (time.time() - now)
        now = time.time()
        for i in range(100000):
            method_mgilson(dCF3v*m)
        print "mgilson's method: %r" % (time.time() - now)

timer()

This will run the test each time on a larger set of data:

>>> 
timing the speed using multiplier: 1
inbar's method: 0.18899989128112793
mgilson's method: 0.192000150680542
timing the speed using multiplier: 10
inbar's method: 0.8540000915527344
mgilson's method: 0.8229999542236328
timing the speed using multiplier: 100
inbar's method: 7.287999868392944
mgilson's method: 7.45199990272522
timing the speed using multiplier: 1000
inbar's method: 71.42099976539612
mgilson's method: 77.18499994277954

As you can see, on larger amounts of data. It is faster. The only reason is is slower is because it takes time to initiate vals, and since I run the functions many, many times, it seems much slower, but if you are running this only once, then you should feel no difference for smaller data sets, but you should feel a large difference for large data sets. (a few seconds at only 1000 times)

Upvotes: 1

Matt Williamson
Matt Williamson

Reputation: 40223

It's because you have a list of lists of tuples, not just a list of tuples. Please consider the following code, or you can just change your x[1] to x[0][1].

>>> max(abs(x[0][1]) for x in dCF3v)
44706.76171875

This uses a built in function max which picks the largest element in an iterable and a generator to map the abs function to each element which will keep it quick and memory efficient.

Upvotes: 1

kiriloff
kiriloff

Reputation: 26333

Simply do

dCF3v=[[(1.90689635276794, -44706.76171875)],
       [(1.90689635276794, -44706.76171875)],
       [(1.90689635276794, -44706.76171875)],
       [(1.90689635276794, -44706.76171875)]
      ]

M = max([x[0][1] for x in dCF3v])

Upvotes: 1

HennyH
HennyH

Reputation: 7944

max(map(lambda t: abs(t[1]),chain(*dCF3v))))

or

max(map(lambda t: abs(t[1]),chain.from_iterable(dCF3v)))

Walkthrough:

print(list(chain(*dCF3v)))
print([abs(t[1]) for t in list(chain(*dCF3v))])

Produces:

>>> 
[(1.90689635276794, -44706.76171875), (1.90689635276794, -44706.76171875), (1.90689635276794, -44706.76171875), (1.90689635276794, -44706.76171875)]
[44706.76171875, 44706.76171875, 44706.76171875, 44706.76171875]

Upvotes: 1

Óscar López
Óscar López

Reputation: 236124

Use the max function for this, it's perhaps the most straightforward solution:

max(dCF3v, key=lambda x: abs(x[0][1]))[0][1]
=> -44706.76171875

Upvotes: 1

mgilson
mgilson

Reputation: 310079

You have a list which holds lists which hold a tuple. So, you probably want abs(x[0][1]).
Then you command can simply be:

max(abs(x[0][1]) for x in dCF3v)

More to the point, you probably actually want to change the data structure to a list holding tuples:

dCF3v = [x[0] for x in dCF3v]

which then would look like:

max(abs(x[0]) for x in dCF3v)

Or, if you wanted the entire tuple to be returned instead of just the second element:

max(dCF3v,key=lambda x:abs(x[0]))

Upvotes: 4

Related Questions