Mathematica Asked by Eriek on August 11, 2020
I want to find two sublists in a list by an element they contain, and then union them, keeping them in the list.
I have this code that seems to do the job, but it seems rather clunky. Is there a better way to do it?
It finds the sublists from the example list ‘groups’ containing b and g, then unions them. You have to do the check to verify that the elements don’t belong to the same sub-list already, or else you end up deleting the sub-list they’re both contained in.
The master list will always be two levels deep, and wouldn’t have any duplicates.
groups = {{a}, {b, c}, {d}, {e, f, g}}
firstPart = b;
secondPart = g;
fPAddress = Part[Position[groups, firstPart, 2], 1, 1];
sPAddress = Part[Position[groups, secondPart, 2], 1, 1];
If[fPAddress != sPAddress,
groups = ReplacePart[groups, fPAddress ->
Union[
Part[groups, fPAddress],
Part[groups, sPAddress]
]
];
groups = Delete[groups, sPAddress];
]
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.
Correct answer by C. E. on August 11, 2020
Flatten /@ Gather[groups, MemberQ[#1, b | g] && MemberQ[#2, b | g] &]
Answered by march on August 11, 2020
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}}
Answered by kglr on August 11, 2020
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP