2
$\begingroup$

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?

$\endgroup$
2
  • 1
    $\begingroup$ Possible duplicates: (13414), (51541) $\endgroup$
    – Mr.Wizard
    Commented May 12, 2015 at 9:45
  • $\begingroup$ Has anyone compared the efficiency of the methods described with (list1 + list2 + Abs[list1-list2])/2? $\endgroup$ Commented Apr 9 at 0:13

3 Answers 3

8
$\begingroup$
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];
MapThread[Max, {list1, list2}] // AbsoluteTiming

{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
]

See this for further reading.

$\endgroup$
3
  • $\begingroup$ Dear LLlAMnYP, this is what I wanted. Can that be done also with 2 dimensional lists e.g. Dimensions[list]={720,577}? $\endgroup$
    – mrz
    Commented May 12, 2015 at 9:47
  • $\begingroup$ 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}}? $\endgroup$
    – LLlAMnYP
    Commented May 12, 2015 at 9:53
  • $\begingroup$ 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. $\endgroup$
    – mrz
    Commented May 12, 2015 at 9:58
7
$\begingroup$

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];

ThreadedMax[l1, .5]; //AbsoluteTiming

{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

$\endgroup$
1
  • $\begingroup$ 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. $\endgroup$
    – LLlAMnYP
    Commented Sep 18, 2017 at 11:22
5
$\begingroup$

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

Internal`MaxAbs[{2, 3, 5, 4, 1, 8, 7} , {1, 4, 6, 3, 2, 8, 8}]

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

Or

Random`Private`MapThreadMax[{{2, 3, 5, 4, 1, 8, 7}, {1, 4, 6, 3, 2, 8, 8}}]

will give a same result

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.