If your test can described as a binary pass/fail and it will only be applied at the first level of a List
it is likely most efficient to use GroupBy
or GatherBy
. GroupBy
makes it easy to order the result e.g. always pass (true) first:
GroupBy[Range@20, PrimeQ] /@ {True, False}
{{2, 3, 5, 7, 11, 13, 17, 19}, {1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20}}
If you are using an earlier version of Mathematica you will have to order the result of GatherBy
:
SortBy[GatherBy[Range@20, PrimeQ], 1 - Boole @ PrimeQ @ First @ # &]
{{2, 3, 5, 7, 11, 13, 17, 19}, {1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20}}
However Cases
does more than this:
- it works on arbitrary expressions
- it works with patterns
- it performs replacements
- it takes a levelspec and the
Heads
option
The earlier answers did not address these points, therefore I shall, with:
separate[expr_, (L_ -> R_) | (L_ :> R_) | L_, arg___] :=
Quiet @ Replace[L | _?(Sow@#; &) :> R, _[x_] :> x] //
Reap[Cases[expr, #, arg], _, Sequence @@ #2 &] &
The syntax is the same as Cases
including levelspec and the Heads
option, as these are passed directly to Cases
itself.
_?(Sow@#; &)
serves as a fall-through when the given pattern does not match, therefore only non-matches are sown.
Examples:
separate[Range@10, x_?OddQ :> x/2]
{{1/2, 3/2, 5/2, 7/2, 9/2}, {2, 4, 6, 8, 10}}
separate[
{{foo, Pi}, -9.3, {False, 1.1}, 1, f[5, 7], True, 3/4},
_[x_, _] :> x
]
{{foo, False, 5, 3}, {-9.3, 1, True}} (* 3 is split from Rational[3, 4] *)
separate[
{{foo, Pi}, -9.3, {False, 1.1}, 1, f[5, 7], True, 3/4},
_Symbol, {2}, Heads -> True
]
{{List, foo, π, List, False, f}, {1.1, 5, 7}}
GatherBy
. That aside, the other points you brought up were helpful. $\endgroup$