I'm trying to efficiently generate tuples of lists of objects that satisfy a given criterion. The similar questions that I have found on this website end up finding a specific workaround for the given problem.
An inefficient way of doing what I want is
Select[Tuples[lists] , criterion]
which is inefficient because MMA first needs to generate and store all the tuples.
I'm thinking of using Outer
, but I'm not sure how. I've tried something that in my head should work but in reality it does not:
Outer[If[#1 === a || #2 === 2, {##}] &, {a, b, c}, Range[2]]
(* {{{a, 1}, {a, 2}}, {Null, {b, 2}}, {Null, {c, 2}}} *)
What it wants to do is to leave the tuple in place if it satisfies the criterion or else remove it: I would like the output to be (in this case)
(* {{{a, 1}, {a, 2}}, {{b, 2}}, {{c, 2}}} *)
How do I do it?
EDIT:
Thanks to the comments I have put to together this solution (which gives the same output of Select[Tuples[{list1,list2,...}], criterion@@##]
):
f = Flatten[Outer[If[criterion@Flatten[{##}], Flatten[{##}], Nothing]&, ##, 1], 1] &
Fold[f, {list1, list2,list3,...}]
Which also allows one to apply the criterion on all the elements of a tuple.
Outer
will work if you specifyNothing
as the third argument ofIf
$\endgroup$Nothing
! (And I love this paradoxical admission) $\endgroup$## &[]
. I still use this because I still have V10.0. $\endgroup$##&[]
evaluates toSequence[]
which is broader in scope thanNothing
. But, the biggest difference, AFAIK, is that they have different reactions toHold
.Sequence
requires theSequenceHold
attribute to hold it,Nothing
is fine withHoldAll
and its kin, e.g.If[a, first, Nothing]
vs.If[a, first, Sequence[]]
. Hence, the use of the function. $\endgroup$Nothing
only works inList
andAssociation
, so in a lot of cases where##&[]
is needed,Nothing
won't work. $\endgroup$