2

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]
jpcgandre
  • 1,487
  • 5
  • 31
  • 55
  • 1
    You should use a nested for loop, like you said or have a look at that maybe: http://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-pythonn and the flatten function: http://rightfootin.blogspot.de/2006/09/more-on-python-flatten.html – User May 02 '13 at 14:46

6 Answers6

4

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]))
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • yeah after he ripped mine off haha – Matt Williamson May 02 '13 at 15:11
  • @mgilson: If for each row of the list there was a different max value how can I know what is the row which contains the max of max values? – jpcgandre May 02 '13 at 15:11
  • 1
    @jpcgandre -- something like `max(dCf3v,key=max)` if I understand you correctly. If you still want absolute values, it's a little trickier: `max(dCf3v,key=lambda row:max(abs(item) for item in row))` – mgilson May 02 '13 at 15:15
  • @mgilson: What I'd like to have besides the maximum value is the row index at which this value occurs: like row 0 or row 2 for example – jpcgandre May 02 '13 at 15:21
1

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.

Matt Williamson
  • 39,165
  • 10
  • 64
  • 72
1
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]
HennyH
  • 7,794
  • 2
  • 29
  • 39
  • Really? This seems much too complicated and you lost the absolute value ... (also, use `chain.from_iterable(dCF3v)` rather than `chain(*dCF3v)`) – mgilson May 02 '13 at 14:54
1

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
Óscar López
  • 232,561
  • 37
  • 312
  • 386
  • You lost the absolute value. Additionally, this will return the entire list containing the tuple with the maximal second element (rather than just the maximal second element) – mgilson May 02 '13 at 14:55
1

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)

Community
  • 1
  • 1
Inbar Rose
  • 41,843
  • 24
  • 85
  • 131
  • I'm not buying that this is any faster than `max(abs(x[0][1]) for x in dCF3v)` ... Can you show any proof? How does this avoid the max function looking up indices like `x[0][1]`? Ultimately, when it gets to the `max` function, doesn't the generator object look exactly the same? – mgilson May 02 '13 at 15:08
  • 1
    I will put up some timers in a moment. – Inbar Rose May 02 '13 at 15:10
1

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])
kiriloff
  • 25,609
  • 37
  • 148
  • 229