With Scala's Set, is there a method analog to the containsAll method in Java's Set?
Asked Answered
H

4

26

While working through converting some Java code over to Scala, I discovered while there is a contains method for Scala's Set, there isn't a containsAll method. Am I just missing the correct method name?

Here's a bit of code I worked up to fill in the gap so I could quickly get back to working. Is it sufficient, or am I missing some subtlety?

  def containsAll[A](set: Set[A], subset: Set[A]): Boolean =
    if (set.size >= subset.size)
      subset.forall(a => set.contains(a))
    else
      false
Haematin answered 24/2, 2015 at 20:38 Comment(0)
H
41

There is subsetOf, which tests whether or not the elements of a Set are contained within another Set. (Kind of the reverse in terms of the expression)

val set = Set(1,2,3,4)
val subset = Set(1,2)

scala> subset.subsetOf(set)
res0: Boolean = true

scala> set.subsetOf(subset)
res1: Boolean = false
Headless answered 24/2, 2015 at 20:43 Comment(1)
Ah. Very nice. It's a bit counterintutive in that it is reversed from Java. But it certainly does what I need. Tysvm for your rapid response.Haematin
E
8

In Scala, Set is equipped with set operations such as intersect, thus for instance

set.intersect(subset) == subset

conveys the semantics of containsAll, even that subsetOf as already mentioned proves the most succinct.

Elishaelision answered 24/2, 2015 at 23:2 Comment(1)
Isn't this substantially less performant on sets of very large size (imagine millions of entries)? IOW, now there are two operations, performing the intersection and then performing the equivalence check. It seems a single pass through the first set testing for elements within the second set would be far preferable and far more performant.Haematin
Y
7

It's worth adding that you can make derived helper methods like containsAll available on Set[T] if you want, by using an implicit enriched class. You might also consider making a variadic overload:

implicit class RichSet[T](val x: Set[T]) extends AnyVal {
    def containsAll(y: Set[T]): Boolean = y.subsetOf(x)
    def containsAll(y: T*): Boolean = x.containsAll(y.toSet)
}

So then you can do:

Set(1, 2, 3).containsAll(Set(1, 2))

Or:

Set(1, 2, 3).containsAll(1, 2)
Yong answered 25/2, 2015 at 0:8 Comment(3)
Very nicely done! I will be definitely adding this to my library.Haematin
What's the reasoning behind explicitly using 'extends AnyVal' as opposed to leaving that implied?Haematin
It is more efficient. From the docs: "...it is possible to define a subclass of AnyVal called a user-defined value class which is treated specially by the compiler. Properly-defined user value classes provide a way to improve performance on user-defined types by avoiding object allocation at runtime, and by replacing virtual method invocations with static method invocations." Read more about AnyVal and user-defined value classes here: scala-lang.org/api/2.11.4/index.html#scala.AnyValYong
J
2

Previous answers are all good, I'm just throwing-in another option. This one would also work with Lists which don't have subsetOf method:

Set(1,2,3) forall(Set(3, 2, 1) contains)
Janeenjanek answered 20/11, 2019 at 15:21 Comment(1)
Beware of duplicates when working with List.Mantelpiece

© 2022 - 2024 — McMap. All rights reserved.