# Get sublists by pattern?

Consider the following list as an example:

l = {a b,  a c d,  b c,  d e};


I would like to have a function that breaks up any list into disjoint sublists based on patterns, i.e.:

patternSeparate[l,{!FreeQ[#,a]&,!FreeQ[#,b]&}]


{{a b, a c d},{bc},{de}}

Here the first sublist contains all entries that are not free of a, the second sublist contains all remaining entries that are not free of b, and third sublist contains all entries that did not match with any previously tested patterns and are remaining at the end. No entry appears twice. Note that having two patterns is just an example and ideally this function should be able to test for any number of patterns.

I know how to write this function as a Do loop with nested If statements. But I thought this sort of breaking up of lists based on patterns seems general enough that an actual Mathematica function for this might exist. Is there such a built in function? If not, maybe there is an efficient way to implement it? Thanks for any suggestion!

I'm not aware of a built-in function but here is one way. You asked about patterns (as you would use in Cases) but the example shows functions (as you would use in Select) so I made it work both ways.

split[list_, {f1_, fn__}, g : Select | Cases] :=
With[{a = g[list, f1]}, {a, Sequence @@ split[Complement[list, a], {fn}, g]}]

split[list_, {f1_}, g : Select | Cases] :=
With[{a = g[list, f1]}, {a, Complement[list, a]}]

l = {a b, a c d, b c, d e};

split[l, {MemberQ[a], MemberQ[b]}, Select]
(* {{a b, a c d}, {b c}, {d e}} *)

split[l, {_ a, _ b}, Cases]
(* {{a b, a c d}, {b c}, {d e}} *)