SubsetQ[] without ignoring duplicates
One way:
ContainsElements[set_, elements_] := Module[{labels, counts},
{labels, counts} = Transpose@Tally[elements];
SubsetQ[set, elements] && And @@ GreaterEqual @@@ Transpose[{labels /. Rule @@@ Tally[set], counts}]
]
Examples:
ContainsElements[{1, 1, 1, 1, 1}, {1, 1, 1}]
(* True *)
ContainsElements[{1, 1, 1}, {1, 1, 1, 1, 1}]
(* False *)
I like Counts
for this:
SubmultisetQ[list1_, list2_] :=
With[{c1 = Counts[list1], c2 = Counts[list2]},
SubsetQ[Keys@c1, Keys@c2] &&
AllTrue[MapThread[GreaterEqual, KeyIntersection[{c1, c2}]],
Identity]];
SubmultisetQ[{1, 2, 1, 1}, {1, 1, 1}]
(* True *)
SubmultisetQ[{1, 2, 2, 1}, {1, 1, 1}]
(* False *)
Proposition
Here is a pattern-matching approach:
Attributes[oList] = Orderless;
sublistQ[{s1___}, {s2___}] := MatchQ[oList[s1], oList[s2, ___]];
Taking the examples of Pillsy:
sublistQ[{1, 2, 1, 1}, {1, 1, 1}]
(* True *)
sublistQ[{1, 2, 2, 1}, {1, 1, 1}]
(* False *)
Proposition 2 (update)
This alternative is faster (see below for updated timings):
sublist2Q[l_List, {s___}] := MatchQ[l, {OrderlessPatternSequence[s, ___]}]
Timings
The best performance amongst the solutions proposed so far will depend on the structure of the input lists. (And so does the scaling for each of them.)
As a few examples, here sublistQ
and sublist2Q
perform better
list = Range[10^5];
list1 = RandomSample[list, 10^5];
list2 = RandomSample[list, 10^4];
SubmultisetQ[list1, list2] // AbsoluteTiming
(* {0.69972, True} *)
MultiplicitySubsetQ[list1, list2] // AbsoluteTiming
(* {0.573459, True} *)
sublistQ[list1, list2] // AbsoluteTiming
(* {0.0750208, True} *)
sublist2Q[list1, list2] // AbsoluteTiming
(* {0.0639587, True} *)
while in what follows SubmultisetQ
is the fastest
list1 = RandomInteger[10, 10^5];
list2 = RandomInteger[10, 5];
SubmultisetQ[list1, list2] // RepeatedTiming
(* {0.00025, True} *)
MultiplicitySubsetQ[list1, list2] // RepeatedTiming
(* {0.105, True} *)
sublistQ[list1, list2] // RepeatedTiming
(* {0.029, True} *)
sublist2Q[list1, list2] // RepeatedTiming
(* {0.027, True} *)