Find sublists in a list by contents, then union them
Using rules:
groups //. {a___, x : {___, b | g, ___}, b___, y : {___, b | g, ___}, c___} :>
{a, Union[x, y], b, c}
This behaves differently compared to your code when there are more than two sublists which contain either b
or g
, in that it will take the union of all of them whereas your code doesn't do that. I hope this is what you intended, or perhaps it's never the case that there are more than two sublists involved?
Or, inspired by march's solution, we might also write
{hasNot, has} = GatherBy[groups, MemberQ[b | g]];
Append[hasNot, Union @@ has]
which can also be written
Append[#, Union @@ #2] & @@ GatherBy[groups, MemberQ[b | g]]
MemberQ
can be replaced by ContainsAny
. If performance is important, one might try this.
Flatten /@ Gather[groups, MemberQ[#1, b | g] && MemberQ[#2, b | g] &]
ClearAll[conditionalUnion]
conditionalUnion[test_] := Reap[
If[test @ #,
Sow[#, Apply @ Union],
Sow[#, Apply @ Sequence]] & /@ #,
_, Construct][[2]] &;
Examples:
conditionalUnion[MatchQ[{___, b | g, ___}]] @ groups
{{a}, {d}, {b, c, e, f, g}}
conditionalUnion[ContainsAny[{b, g}]] @ groups
{{a}, {d}, {b, c, e, f, g}}
Take the union of sublists with lengths less than 3:
conditionalUnion[Length[#] <= 2&] @ groups
{{a, b, c, d}, {e, f, g}}