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.
Fold[Outer[criterion,##]& , list1, {list2,..}]or do you mean something else? Each of my lists is a list of associations, and my criterion is that all the lists of associations in each tuple must be "overlapping" on at least two associations with respect to the value of a given key. (example: considering the key "b", {<|"a"->1,"b"->2|>, <|"a"->1,"b"->3|>} overlaps with {<|"a"->1,"b"->2|>, <|"a"->1,"b"->4|>} only for one value (the value 2) and a tuple containing these two lists would be discarded.) – Ziofil Feb 03 '16 at 21:22Outerwill work if you specifyNothingas the third argument ofIf– Simon Woods Feb 03 '16 at 21:24Nothing! (And I love this paradoxical admission) – Ziofil Feb 03 '16 at 21:26Nothingis a very new function. So, i'm not surprised you knew nothing about it. – rcollyer Feb 03 '16 at 21:51## &[]. I still use this because I still have V10.0. – march Feb 03 '16 at 22:14##&[]evaluates toSequence[]which is broader in scope thanNothing. But, the biggest difference, AFAIK, is that they have different reactions toHold.Sequencerequires theSequenceHoldattribute to hold it,Nothingis fine withHoldAlland its kin, e.g.If[a, first, Nothing]vs.If[a, first, Sequence[]]. Hence, the use of the function. – rcollyer Feb 04 '16 at 04:52##&[]in some silly situations involving more complicated versions of something likeWhich[expr1, ## &[], expr2, else]vsWhich[expr1, Sequence[], expr2, else], where clearly the first works and the second doesn't. Anyway, someday I'll have V10.(>1), and I can useNothing. – march Feb 04 '16 at 05:11Outerstill tries all combinations of elements in the two lists, which may or may not be wasteful, given the lists and/or the comparison function. But unless the associations in the lists have a sort of predeterminable structure, you probably need to compare all of them, so your solution will be fine =) – Marius Ladegård Meyer Feb 04 '16 at 05:12Nothingonly works inListandAssociation, so in a lot of cases where##&[]is needed,Nothingwon't work. – rcollyer Feb 04 '16 at 15:55