TransWikia.com

Find sublists in a list by contents, then union them

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];
 ]

3 Answers

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

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP