Group Abstract Group Abstract

Message Boards Message Boards

2
|
5K Views
|
6 Replies
|
9 Total Likes
View groups...
Share
Share this post:

Test if a list contains another list, observing multiplicities?

Posted 6 years ago

As a novice I am looking for an elegant and fast function that tells me if the first list contains all elements of a second list, observing multiplicities:

TestQ[{a,b,c},{c,b}] -> True
TestQ[{a,b,c},{c,c}] -> False
TestQ[{a,b,c,c},{c,a,c}] -> True

Thank you all, Thomas

POSTED BY: Thomas Vogler
6 Replies

My solution would be as follows:

ClearAll[ContainsAllMultiplicities]
ContainsAllMultiplicities[l1_List, l2_List] := 
 Module[{c1, c2, m, il1, il2},
  c1 = {1, #} & /@ Counts[l1];
  c2 = {2, #} & /@ Counts[l2];
  m = Merge[{c1, c2}, Identity];
  m = Values[m];
  If[MemberQ[m, {{2, _}}],
   False
   ,
   m = DeleteCases[m, {{1, _}}];
   m = SortBy[First] /@ m;
   m = m[[All, All, 2]];
   AllTrue[m, GreaterEqual @@ # &]
   ]
  ]

Some test code:

ContainsAllMultiplicities[{a, b, c}, {c, b}]
ContainsAllMultiplicities[{a, b, c}, {c, c}]
ContainsAllMultiplicities[{a, b, c}, {c, c, d}]
ContainsAllMultiplicities[{a, b, c, c}, {c, a, c}]
ContainsAllMultiplicities[{a, b, c, c}, {c, a, c, b}]
ContainsAllMultiplicities[{a, b, c, c}, {c, a, c, b, c}]

returning:

True
False
False
True
True    
False

Should work fast, especially for large listsÂ…

POSTED BY: Sander Huisman
POSTED BY: Thomas Vogler
Posted 6 years ago

But you erroneously give containsQ[{a,b,c,b},{b}] -> False

Sorry about that. I misinterpreted the requirement

observing multiplicities

to mean that the multiplicities in the superset/subset lists must match.

POSTED BY: Rohit Namjoshi

I'm sure this is not optimal, but one might sort both and try matching the first to a pattern that alternates blank null sequences with the second.

testQ[l1_List, l2_List] :=
 Module[
  {sl1 = Sort[l1], sl2 = Sort[l2], pat},
  pat = Riffle[ConstantArray[BlankNullSequence[], Length[sl2] + 1], 
    sl2];
  MatchQ[sl1, pat]]

testQ[{a, b, c}, {c, b}]
testQ[{a, b, c}, {c, c}]
testQ[{a, b, c, c}, {c, a, c}]

(* Out[1384]= True

Out[1385]= False

Out[1386]= True *)
POSTED BY: Daniel Lichtblau
Posted 6 years ago

ContainsAll does not consider multiplicities so maybe

containsQ[l1_List, l2_List] := ContainsAll[Tally[l1], Tally[l2]];

Note that ContainsAll[list, {}] always returns True.

POSTED BY: Rohit Namjoshi

Perhaps look at ContainsAll?

POSTED BY: Sander Huisman
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard