11
$\begingroup$

I would like to compare two arrays:

m = {a,b,c,d,d,f};
n = {b,b,a,d,d,e};

and get:

{0,b,0,d,d,0}

I have tried all kinds of things, like:

m = {a,b,c,d,d,f};
n = {b,b,a,d,d,e};
Transpose[{m, n}];
If[{x_ == y_} :> x, 0]

but clearly, I have no idea what I am doing! I am (obviously) very new to Mathematica, and would greatly appreciate any help.

$\endgroup$
  • $\begingroup$ Will the elements always be symbols, or will they sometimes be values, or characters/strings? $\endgroup$ – C. E. Oct 9 '13 at 17:16

11 Answers 11

18
$\begingroup$

The following solution may look a bit weird, but has an advantage of automatically being very efficient for numerical large lists:

m * (1 - Block[{Unitize}, _Unitize = 1; #] & [ Unitize[m - n]])
| improve this answer | |
$\endgroup$
  • $\begingroup$ +1. Are you still going to write that part 2 of your book? I know you're super busy, just curious. $\endgroup$ – RunnyKine Oct 9 '13 at 17:38
  • 2
    $\begingroup$ @RunnyKine Thanks. Re: book - yes, I am going to, although it is not yet clear what the format of it will be, or set the exact time frame for it. $\endgroup$ – Leonid Shifrin Oct 9 '13 at 17:42
  • $\begingroup$ Thanks for replying. Good to know. The first one is a classic by the way. $\endgroup$ – RunnyKine Oct 9 '13 at 17:45
  • $\begingroup$ @RunnyKine Well, thanks :) I wrote it when I knew so much less than I do now (which I do in a big part due to this community), and I can see many flaws in the book now - so it's always good to know that it is not totally bad :) $\endgroup$ – Leonid Shifrin Oct 9 '13 at 17:47
10
$\begingroup$
MapThread[If[SameQ[#1, #2], #1, 0] &, {m, n}]

or

Transpose[{m, n}] /. {p_, q_} :> If[SameQ[p, q], p, 0]
| improve this answer | |
$\endgroup$
  • $\begingroup$ Many thanks, Chris! $\endgroup$ – martin Oct 9 '13 at 17:24
8
$\begingroup$
Inner[ If[ #1 === #2, #1, 0] &, m, n, List]
{0, b, 0, d, d, 0}

or with Transpose and Apply:

If[#1 === #2, #1, 0] & @@@ Transpose[{m, n}]
| improve this answer | |
$\endgroup$
5
$\begingroup$

Here's an unconventional way, which I think should be reasonably fast (thanks to Leonid for spotting a flaw):

Replace[m + n, _Plus -> 0, {1}] / 2
(* {0, b, 0, d, d, 0} *)

The idea is that a + b will have the head Plus, whereas a + a is 2 a, which has the head Times. Needless to say, a severe drawback of this approach is when the elements of the lists are numbers...

| improve this answer | |
$\endgroup$
  • $\begingroup$ @LeonidShifrin Oops... Thanks! :D $\endgroup$ – rm -rf Oct 9 '13 at 17:59
5
$\begingroup$

And yet another variation using rules:

Thread@{m, n} /. {{p_, p_} :> p, {_, _} :> 0}

(Also Thread instead of Transpose for extra differenceness)

| improve this answer | |
$\endgroup$
4
$\begingroup$

Here's a straightforward approach quite similar to your first attempt, which has the feature that it will work for numbers as well as symbols.

m = {1, b, c, 5.0, d, f};
n = {3, b, a, 5.0, d, e};
Table[If[m[[i]] === n[[i]], m[[i]], 0], {i, Length[m]}]

{0, b, 0, 5., d, 0}
| improve this answer | |
$\endgroup$
3
$\begingroup$
m (1 - Sign[Length /@ (m - n)])
(*{0, b, 0, d, d, 0}*)
| improve this answer | |
$\endgroup$
2
$\begingroup$

My solution:

m * Boole@MapThread[SameQ, {m, n}]

{0, b, 0, d, d, 0}


And here's the comparison:

m = RandomChoice[{a, b, c, d, e, f, g, h, i, j, k}, 1000000];
n = RandomChoice[{a, b, c, d, e, f, g, h, i, j, k}, 1000000];

(*Leonid Shifrin*)
m*(1 - Block[{Unitize}, _Unitize = 1; #] &[Unitize[m - n]]); // AbsoluteTiming

(*Artes*)
Inner[If[#1 === #2, #1, 0] &, m, n, List]; // AbsoluteTiming

(*Artes*)
If[#1 === #2, #1, 0] & @@@ Transpose[{m, n}]; // AbsoluteTiming

(*Chris Degnen*)
MapThread[If[SameQ[#1, #2], #1, 0] &, {m, n}]; // AbsoluteTiming

(*Chris Degnen*)
Transpose[{m, n}] /. {p_, q_} :> If[SameQ[p, q], p, 0]; // AbsoluteTiming

(*rm-rf*)
Replace[m + n, _Plus -> 0, {1}]/2; // AbsoluteTiming(*rm-rf*)

(*wxffles*)
Thread@{m, n} /. {{p_, p_} :> p, {_, _} :> 0}; // AbsoluteTiming

(*chyaong*)
m (1 - Sign[Length /@ (m - n)]); // AbsoluteTiming

(*RunnyKine*)
n*Replace[m/n, {1 -> 1, _ -> 0}, {1}]; // AbsoluteTiming

(*alephalpha*)
m * Boole@MapThread[SameQ, {m, n}]; // AbsoluteTiming

{5.359334, Null}
{1.688222, Null}
{1.920503, Null}
{1.629107, Null}
{2.132745, Null}
{1.964956, Null}
{1.396690, Null}
{3.478013, Null}
{3.582479, Null}
{1.933204, Null}

| improve this answer | |
$\endgroup$
  • $\begingroup$ @Artes It refers to Loenid's one. $\endgroup$ – alephalpha Oct 11 '13 at 16:32
1
$\begingroup$

With inspiration from rm -rf here's one that should also work with numbers (If there are no zeros).

n * Replace[m / n, {1 -> 1, _ -> 0}, {1}]

{0, b, 0, d, d, 0}

| improve this answer | |
$\endgroup$
1
$\begingroup$

Here is another one:

m * (1 - Abs[MapThread[Order, {m, n}]])
| improve this answer | |
$\endgroup$
0
$\begingroup$

Idea of sparseArray can be pretty useful in case of large matrices or on extending it to multi-dimensional.

Block[{m = {a, b, c, d, d, f}, n = {b, b, a, d, d, e}, sep, 
  sum}, {sep = ArrayPad[#, {0, Length[m] - Length[#]}] & /@ 
    Flatten[Normal[SparseArray[{1, #} -> n[[#]]]] & /@ 
      Flatten[Position[Subtract[m, n], 0]], 1], 
  sum = ConstantArray[0, Length[m]]}; 
 Table[sum = sep[[i]] + sum, {i, Length[sep]}] // Last]

{0, b, 0, d, d, 0}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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