14
$\begingroup$

So I have 2 lists of 10000+ lists of 3 numbers, e.g.

{{1,2,3},{4,5,6},{7,8,9},...} {{2,1,3},{4,5,6},{41,2,0},...} 

Wanting a result like

{2,...} 

Getting some sort of list of True/False is also probably enough, like this:

{False,True,False,...} 

I guess I could use Position once I've done that.

I tried to use Thread, as below:

Thread[{{a, b}, {c, d}, {e, f}} == {{a, b}, {d, e}, {f, e}}] 

which gives the True/False output

{True, {c, d} == {d, e}, {e, f} == {f, e}} 

But as soon as there are actual numbers in place, it doesn't work:

Thread[{{1, 2}, {2, 3}, {4, 5}} == {{1, 3}, {2, 3}, {4, 5}}] 

Returns

False 

I'd really appreciate any help you could give.

Thanks,

H

$\endgroup$

4 Answers 4

10
$\begingroup$

One possible way of doing it:

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {1, 2, 3}}; b = {{2, 1, 3}, {4, 5, 6}, {41, 2, 0}, {1, 2, 3}}; Position[MapThread[Equal, {a, b}], True] 

The output reads: {{2}, {4}}

In my code, it compares the elements for each position, but it doesn't "cross check" them, i.e.it doesn't consider that the element n of list a could be equal to element m!=n of list b

EDIT: note that the solution provided by @Henrik Schumacher is much faster :)

a = RandomInteger[{0, 4}, {100000, 3}]; b = RandomInteger[{0, 4}, {100000, 3}]; RepeatedTiming@Position[MapThread[Equal, {a, b}], True][[1]] (*0.089*) RepeatedTiming@ Position[Unitize[Subtract[a, b]].ConstantArray[1, Dimensions[a][[2]]], 0, 1][[1]] (*0.0057*) 
$\endgroup$
1
  • $\begingroup$ That's perfect and very simple. I tried to do a similar thing but I guess I messed up the syntax or something. Indeed I didn't want any cross-checking, comparing like-for-like position is an important part of my problem. Thanks so much! I'll mark as the answer as soon as I can $\endgroup$ Commented Jun 5, 2018 at 8:10
11
$\begingroup$
a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {1, 2, 3}}; b = {{2, 1, 3}, {4, 5, 6}, {41, 2, 0}, {1, 2, 3}}; Pick[Range@Length@a, Total /@ Unitize[Subtract[a, b]], 0] 

{2,4}

Or using @Henrik's idea of using Dot in in the second argument of Pick:

Pick[Range @ Length @ a, Unitize[Subtract[a, b]].ConstantArray[1, Dimensions[a][[2]]], 0] 

{2, 4}

$\endgroup$
11
$\begingroup$

This should be rather fast for very long packed arrays of integers.

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {1, 2, 3}}; b = {{2, 1, 3}, {4, 5, 6}, {41, 2, 0}, {1, 2, 3}}; f2[a_,b_] := Position[Unitize[Subtract[a, b]].ConstantArray[1, Dimensions[a][[2]]], 0, 1]; f2[a,b] 

{{2}, {4}}

More complicated but twice as fast (thanks to Carl Woll for the idea to use 1. instead of 1 in the ConstantArray):

f3[a_, b_] := SparseArray[ Unitize[ Unitize[Subtract[a, b]].ConstantArray[1., Dimensions[a][[2]]]], {Length[a]}, 1 ]["NonzeroPositions"]; RandomSeed[12345]; {a, b} = RandomInteger[{1, 9}, {2, 1000000, 3}]; r2 = f2[a, b]; // RepeatedTiming // First r3 = f3[a, b]; // RepeatedTiming // First r2 == r3 

0.060

0.021

True

$\endgroup$
2
  • $\begingroup$ Using ConstantArray[1., Dimensions[a][[2]]] is a bit faster $\endgroup$ Commented Jun 5, 2018 at 18:46
  • $\begingroup$ Thanks, @CarlWoll, that's very good thing to keep in mind! $\endgroup$ Commented Jun 5, 2018 at 21:46
5
$\begingroup$

If you need speed, you could use ugly compiled function:

equalPosInt2 = Last@Compile[{{a, _Integer, 2}, {b, _Integer, 2}}, Module[{result, dimA, dimB, n, m, eq}, result = Internal`Bag@Most@{0}; dimA = Dimensions@a; dimB = Dimensions@b; n = Min[Compile`GetElement[dimA, 1], Compile`GetElement[dimB, 1]]; m = Min[Compile`GetElement[dimA, 2], Compile`GetElement[dimB, 2]]; Do[ eq = True; Do[ If[Compile`GetElement[a, i, j] =!= Compile`GetElement[b, i, j], eq = False; Break[]; ]; , {j, m} ]; If[eq, Internal`StuffBag[result, i]]; , {i, n} ]; Internal`BagPart[result, All] ], CompilationTarget -> "C", RuntimeOptions -> "Speed" ]; 

Basic test:

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {1, 2, 3}}; b = {{2, 1, 3}, {4, 5, 6}, {41, 2, 0}, {1, 2, 3}}; equalPosInt2[a, b] (* {2, 4} *) 

Timings:

fraccalo[a_, b_] := Position[MapThread[Equal, {a, b}], True] f2[a_, b_] := Position[Unitize[Subtract[a, b]].ConstantArray[1, Dimensions[a][[2]]], 0, 1] f3[a_, b_] := SparseArray[Unitize[Unitize[Subtract[a, b]].ConstantArray[1, Dimensions[a][[2]]]], {Length[a]}, 1]["NonzeroPositions"] kglr1[a_, b_] := Pick[Range@Length@a, Total /@ Unitize[Subtract[a, b]], 0] kglr2[a_, b_] := Pick[Range@Length@a, Unitize[Subtract[a, b]].ConstantArray[1, Dimensions[a][[2]]], 0] RandomSeed@12345; {a, b} = RandomInteger[{1, 9}, {2, 1000000, 3}]; r1 = fraccalo[a, b]; // MaxMemoryUsed // RepeatedTiming (*{0.691, 280000672}*) r2 = f2[a, b]; // MaxMemoryUsed // RepeatedTiming (*{0.0803, 64000928}*) r3 = f3[a, b]; // MaxMemoryUsed // RepeatedTiming (*{0.048, 64001120}*) r4 = kglr1[a, b]; // MaxMemoryUsed // RepeatedTiming (*{0.072, 56000904}*) r5 = kglr2[a, b]; // MaxMemoryUsed // RepeatedTiming (*{0.0495, 72001232}*) r6 = equalPosInt2[a, b]; // MaxMemoryUsed // RepeatedTiming (*{0.0054, 29928}*) r1[[All, 1]] === r2[[All, 1]] === r3[[All, 1]] === r4 === r5 === r6 (* True *) 
$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.