Python get max absolute value from different lists

Viewed 110

I am trying to create a function that will find the maximum absolute value for each entry in three lists and combine it into one list.

Given the three lists:

S12 = [-3, 24,   8,  13,  24,  43,  33,  19, -14, -36, -30, -16, -21]
S23 = [13,  5, -67, -98,  37,  30,   9,  11,  -4,   2,  43,  26, -24]
S13 = [ 9, 40,  -2, -26, -25, -19, -25, -31,  36,  23,  39,  47,  29]

I want the code to grab the maximum absolute value, first of -3, 13 and 9 then of 24, 5 and 40 and so on.

I have the following code:

def maxOfThree(s1, s2, s3):
    maxOfThree = s1
    for i in range(len(s1)):
        if abs(s2[i]) > abs(maxOfThree[i]):
            maxOfThree[i] = s2[i]
        elif abs(s3[i]) > abs(maxOfThree[i]):
            maxOfThree[i] = s3[i]
    return maxOfThree

maximumValueInThreeLists = maxOfThree(S12,S23,S13)
print(maximumValueInThreeLists)

The expected result is

[13, 40, -67, -98, 37, 43, 33, -31, 36, -36, 43, 47, 29]

but the output I get is

[13, 40, -67, -98, 37, 43, 33, -31, 36, -36, 43, 26, -24]

I cant figure out what is going wrong with my code, but some of the entries are not correct (in this case the final two, but that is just a coincedence).

4 Answers

This can be done in a single line:

S12 = [-3, 24,   8,  13,  24,  43,  33,  19, -14, -36, -30, -16, -21]
S23 = [13,  5, -67, -98,  37,  30,   9,  11,  -4,   2,  43,  26, -24]
S13 = [ 9, 40,  -2, -26, -25, -19, -25, -31,  36,  23,  39,  47,  29]

res = [max(t, key=abs) for t in zip(S12, S23, S13)]
print(res)  # -> [13, 40, -67, -98, 37, 43, 33, -31, 36, -36, 43, 47, 29]

This can also handle lists with different lengths due to the way zip is implemented. In that case, the shortest list will define the length of the result. If you want the code to assume zeros for the shorter lists you can use zip_longest from itertools instead. Examples of both of thoses behaviors are given below.

Assuming:

S12 = [-3, 24,   8,  13,  24]
S23 = [13,  5, -67, -98,  37,  30]
S13 = [ 9, 40,  -2, -26, -25, -19, -25]

with zip:

res = [max(t, key=abs) for t in zip(S12, S23, S13)]
print(res)  # -> [13, 40, -67, -98, 37]

with itertools.zip_longest:

from itertools import zip_longest
res = [max(t, key=abs) for t in zip_longest(S12, S23, S13, fillvalue=0)]
print(res)  # -> [13, 40, -67, -98, 37, 30, -25]

There are a couple of problems with this code:

  1. you use elif instead of an if in the second comparison. hence if s2 contains a larger value than s1 then no comparison will ever be attempted against s3

  2. you mutate s1, e.g. add print(S12) after running this function. there are various ways of making a (shallow) copy, list(s1) or s1[:] are both fine choices

giving:

def maxOfThree(s1, s2, s3):
    maxOfThree = list(s1)
    for i in range(len(s1)):
        if abs(s2[i]) > abs(maxOfThree[i]):
            maxOfThree[i] = s2[i]
        if abs(s3[i]) > abs(maxOfThree[i]):
            maxOfThree[i] = s3[i]
    return maxOfThree

maximumValueInThreeLists = maxOfThree(S12,S23,S13)
print(maximumValueInThreeLists)

You can do it like this:

S12 = [-3, 24,   8,  13,  24,  43,  33,  19, -14, -36, -30, -16, -21]
S23 = [13,  5, -67, -98,  37,  30,   9,  11,  -4,   2,  43,  26, -24]
S13 = [ 9, 40,  -2, -26, -25, -19, -25, -31,  36,  23,  39,  47,  29]

def abs_max(s1, s2, s3):
    return [sorted(i,key=abs)[-1] for i in zip(s1, s2, s3)]
    # or even better
    # return [max(i,key=abs) for i in zip(s1, s2, s3)]
           

print(abs_max(S12, S23, S13))

returns

[13, 40, -67, -98, 37, 43, 33, -31, 36, -36, 43, 47, 29]
out = []
for i in range(len(S12)):
    out.append(max(S12[i],S23[i],S13[i], key=abs))
out

[13, 40, -67, -98, 37, 43, 33, -31, 36, -36, 43, 47, 29]

or in a single line

[max(i, key=abs) for i in zip(S12,S23,S13)]
Related