I have a task, where I have to combine pairs with a function, but the number of pairs I actually need is much smaller than the number of all pairs. The condition to keep the element is some function of both elements. Originally, I used something like:
Select[Flatten@Outer[function,array1,array2],condition]
However, this creates a huge computational and memory overhead: it generates the entire matrix (which is quickly bigger than RAM, and also takes time to apply function when I'll just throw it away), and then also takes time to filter.
I was looking for a non-procedural way to do this, and it seems most builtins are oriented towards constructing everything and filtering later. Map
is out of the question, so are Table
and Array
: Even leaving Nulls in the array is an overhead, and using Sequence appeared worse. I ended up writing
ApplyIf[f_, a_, b_, condition_] :=
Module[{result = {}, n1 = Length[a], n2 = Length[b], i, j},
For[i = 1, i < n1, i++,
For[j = 1, j < n2, j++,
r1 = a[[i]];
r2 = b[[j]];
If[condition[r1, r2],
AppendTo[result, f[r1, r2]];
]
]
];
result
];
which does solve the memory overhead problem, but being procedural, it's not in the spirit of Mathematica, and I'm also concerned with time complexity of AppendTo
.
Is there a better way to do this?
Is Reap
/ Sow
advisable in these situations?
SparseArray
to reduce memory usage? $\endgroup$For
for good and useSow
/Reap
withDo
. $\endgroup$AppendTo
and procedural programming is to simply chunk my arrays. Alternatively,Reap
andSow
will indeed circumvent the time complexity ofAppendTo
and by using aDo
loop instead of yourFor
loops you can remove the time complexity from all thoseFor
tests and incrementations and whatnot. $\endgroup$Do[f[array[[i]]], {i, Length[array]}]
you can useDo[f[elem], {elem, array}]
. All this will effectively save you theModule
, as you will not need local variables anymore.Reap@Do[If[condition[r1, r2], Sow@f[r1, r2]], {r1, a}, {r2, b}]
$\endgroup$