Replace element in array by checking condition in another list
Update after discussions in comments
I've revised my code to use Replace
with a level spec, and to create rules only from list2, since the latter list can be much smaller than the first list. This provides a speed boost of about 50%.
update[l1_,l2_] := Module[{p, q, r=l1},
p = Replace[
l1[[All,;;2]],
Dispatch @ Thread @ Rule[l2[[All,;;2]], l2[[All,3]]],
{1}
];
q = Replace[p[[All,0]], {List->0,_->1}, {1}];
r[[Pick[Range[Length[l1]], q, 1], 3]] = Pick[p,q,1];
r
]
For your initial example:
update[list1, list2]
{{1, 2, 0}, {1, 3, 1}, {4, 6, 0}, {2, 3, 0}}
For your latest example:
test1={{0.5,0.5,0},{1,1,0},{1.5,1.5,0},{2.0,2.0,0}};
test2={{0.5,0.5,1},{2.0,2.0,1}};
update2[test1,test2]
{{0.5, 0.5, 1}, {1, 1, 0}, {1.5, 1.5, 0}, {2., 2., 1}}
Timing
Since you mention working with large arrays, here's the speed of update
on some made up data:
list1=Sort@RandomReal[1,{10^4,3}];
list2=RandomSample[list1,10^3];
list2[[All,3]]=RandomReal[1,10^3];
update[list1,list2];//AbsoluteTiming
{0.01681, Null}
list1=Sort@RandomReal[1,{10^6,3}];
list2=RandomSample[list1,10^5];
list2[[All,3]]=RandomReal[1,10^5];
update[list1,list2];//AbsoluteTiming
{1.99171, Null}
Old code
update2[l1_,l2_] := Module[{r=l1, l=Join[l2,l1]},
r[[All,3]] = r[[All, ;;2]] /. Dispatch@Thread@Rule[l[[All, ;;2]],l[[All,3]]];
r
]
f[v1_, v2_] := If[Most[v1] == Most[v2], v2, v1];
MapThread[f, {list1, list2}]
which gives you {{1, 2, 0}, {1, 3, 1}, {4, 6, 0}, {2, 3, 0}}
Revised to incorporate your unequal length list condition
Map[(match = Cases[list2, Join[Most[#], {_}]];
If[match == {}, #, match[[1]]]) &, list1]
list1 = {{1, 2, 0}, {1, 3, 0}, {4, 6, 0}, {2, 3, 0}};
list2 = {{3, 2, 1}, {1, 3, 1}, {4, 5, 1}, {4, 3, 1}};
If[Most[#] === Most[#2], #2, #] & @@@ Transpose[{list1, list2}]
{{1, 2, 0}, {1, 3, 1}, {4, 6, 0}, {2, 3, 0}}