# Finding element-wise Max of two lists

I need a compare-operation for two lists of same length (usually > 100000) which does the following:

{2,3,5,4,1,8,7} compare-operation {1,4,6,3,2,8,8} = {2,4,6,4,2,8,8}

The resulting list has at each position the greater (or equal element in case both are equal) of the two lists (because 2>1,4>3,6>5,4>3,2>1,8=8,8>7).

How can that be done?

MapThread[Max, {{2, 3, 5, 4, 1, 8, 7} , {1, 4, 6, 3, 2, 8, 8}}]


{2, 4, 6, 4, 2, 8, 8}

Thread[Unevaluated[Max[{2, 3, 5, 4, 1, 8, 7} , {1, 4, 6, 3, 2, 8, 8}]]]


also works. Unevaluated is necessary, otherwise Max[... evaluates, before Thread acts on it. On the other hand

Thread[Unevaluated[Max[list1, list2]]]


does not work for the same reasons.

list1 = RandomInteger[30, 1*^7];
list2 = RandomInteger[30, 1*^7];


{6.302683, {28, 10, 21, 13 ...

Not too bad for ten million elements. In fact, faster than constructing the lists.

In this simple case however, we can do 10 times better:

(Max /@ Transpose@{list1, list2}) // AbsoluteTiming // First


0.608412

For a list with 2 dimensions the obvious solution is

MapThread[Max, {list1, list2}, 2] // AbsoluteTiming // First


0.702000

Timing is shown for a 10^3 by 10^3 list.

The faster solution uses the, so-to-speak, generalized transpose, which is achieved by using flatten with a matrix as the second argument:

Map[Max, Flatten[{list1, list2}, {{2}, {3}, {1}}], {2}] // AbsoluteTiming // First


0.109200

As before, almost an order of magnitude faster. The general expression for k-dimensional lists would be:

Map[Max, Flatten[{list1, list2}, {{2}, {3}, ..., {k+1}, {1}}], {k}]


Update 18.09.17

Carl Woll's ThreadedMax is hard to beat, but exploiting Compiled listability comes close:

threadMax =
Compile[{{x1, _Integer}, {x2, _Integer}}, Max[x1, x2],
RuntimeAttributes -> {Listable}, Parallelization -> True,
CompilationTarget -> "C", RuntimeOptions -> "Speed"]


It is still a few times slower though and I'd recommend Carl's solution. Simple top-level functions with built-in listability are close to impossible to beat even with compiled functions and are more versatile in the datatypes they accept: e.g., the above threadMax will only work on packed arrays of integers.

If Ramp isn't available in your version of MMA, just like it is in mine (I'm on 10.2), I suggest the following implementation:

ThreadedMax[l1_List, l2_List] :=
With[{diff = Subtract[l1, l2]},
Check[UnitStep[diff] diff + l2, $Failed]]  I would similarly modify Carl's solution like so for better performance: ThreadedMax[l1_List, l2_List] := Check[ Ramp[Subtract[l1, l2]]+l2,$Failed
]


• Dear LLlAMnYP, this is what I wanted. Can that be done also with 2 dimensional lists e.g. Dimensions[list]={720,577}? – mrz May 12 '15 at 9:47
• Do you mean element-wise comparisons at the second level of the lists? As in {{1, 6},{3, 9}} ~~ {{2, 5}, {4, 1}} -> {{2, 6},{4, 9}}? – LLlAMnYP May 12 '15 at 9:53
• You can imagine that I would have two grey level images of 720 rows and 577 columns and I want to produce an resulting image where each pixel brightness corresponds to the higher brightness value of the images. – mrz May 12 '15 at 9:58

For threading the maximum of a list (or array) with a number, you'll be hard pressed to beat the following:

ThreadedMax[l1_List, l2_?NumericQ] := Clip[l1, {l2, Infinity}]


For example:

l1 = RandomReal[1, 10^8];



{0.552601, Null}

For threading the maximum of 2 arrays, the following is the fastest approach I can think of:

ThreadedMax[l1_List, l2_List] := Check[
Ramp[l1-l2]+l2,
$Failed ]  Comparing with the answer by @LLlAMnYP: l1 = RandomReal[1, 10^7]; l2 = RandomReal[1, 10^7]; r1 = ThreadedMax[l1, l2]; //AbsoluteTiming r2 = MapThread[Max, {l1, l2}]; //AbsoluteTiming r3 = Max /@ Transpose[{l1, l2}]; //AbsoluteTiming r1 === r2 === r3  {0.089001, Null} {5.53821, Null} {0.602344, Null} True For arrays with higher rank, we have: l1 = RandomReal[1, {3000, 3000}]; l2 = RandomReal[1, {3000, 3000}]; r1 = ThreadedMax[l1, l2]; //AbsoluteTiming r2 = MapThread[Max, {l1, l2}, 2]; //AbsoluteTiming r3 = Map[Max, Flatten[{l1, l2}, {{2}, {3}, {1}}], {2}]; //AbsoluteTiming r1 === r2 === r3  {0.096501, Null} {5.30103, Null} {0.694005, Null} True • Very nice improvement. Since you're using Listable operations inside your ThreadedMax definition, I see no reason to check the Head of the arguments. ThreadedMax[l1_, l2_] := Check[Ramp[Subtract[l1,l2]]+l2,$Failed] will cover all cases and probably give optimum performance, as per my update. – LLlAMnYP Sep 18 '17 at 11:22

If you are in 11.1 or later verion

ThreadingLayer[Max][{{2, 3, 5, 4, 1, 8, 7} , {1, 4, 6, 3, 2, 8, 8}}]


{2.,4.,6.,4.,2.,8.,8.}

Of course,we have build-in method if you are in old verion

InternalMaxAbs[{2, 3, 5, 4, 1, 8, 7} , {1, 4, 6, 3, 2, 8, 8}]


{2,4,6,4,2,8,8}

Or

RandomPrivateMapThreadMax[{{2, 3, 5, 4, 1, 8, 7}, {1, 4, 6, 3, 2, 8, 8}}]


will give a same result

• +many if I could, this is a brilliant showcase of an undocumented Internal function. An extra ~3-fold speed increase. – LLlAMnYP Sep 18 '17 at 11:29
• Like net function too! – partida Sep 18 '17 at 11:30
• Of course, MaxAbs is Max**Abs`**, but it seems that OPs use-case works with non-negative numbers anyway. – LLlAMnYP Sep 18 '17 at 11:31
• @LLlAMnYP See edit.. – yode Sep 18 '17 at 11:36
• Nonexistent in 10.2, it seems. – LLlAMnYP Sep 18 '17 at 11:38