Categories
Tech

Scala Saturday – The contains and containsSlice Methods

Scala defines the contains method on all its collection classes.

Sets

Let’s say you have a set containing the nicknames of the guys in the band Rush, and you want to see whether a certain person is in the band. Just use contains:

val rush = Set("Dirk", "Lerxst", "Pratt")

val gotAlex = rush contains "Lerxst"
// gotAlex: Boolean = true
val gotAngus = rush contains "Angus"
// gotAngus: Boolean = false

Arrays, Lists, and Vectors (Oh, My!)

Seq and the sequence-like classes all define the contains method:

val rushSeq = Seq("Dirk", "Lerxst", "Pratt")
val rushA = Array("Dirk", "Lerxst", "Pratt")
val rushL = List("Dirk", "Lerxst", "Pratt")
val rushV = Vector("Dirk", "Lerxst", "Pratt")

val gotGene = rushSeq contains "Gene"
// gotGene: Boolean = false
val gotNeil = rushA contains "Pratt"
// gotNeil : Boolean = true
val gotAlex = rushL contains "Lerxst"
// gotAlex : Boolean = true
val gotPeter = rushV contains "Peter"
// gotPeter : Boolean = false

Sequences and the like also define a containsSlice method that takes a sequence and checks it is found in the collection. Order does matter, though:

val gotGedAndAl = rushSeq containsSlice Seq("Dirk", "Lerxst")
// gotGedAndAl: Boolean = true

// rushSeq has "Dirk" before "Lerxst", so the following fails
val gotAlAndGed = rushSeq containsSlice Seq("Lerxst", "Dirk")
// gotAlAndGed: Boolean = false

Strings

Because Scala just uses Java’s String class, we inherit the following from Java:

val gotX = "Lerxst" contains 'x'
// gotX : Boolean = true
val gotA = "Lerxst" contains 'A'
// gotA : Boolean = false

Java overloads contains to accept a String as well as a char:

val gotXs = "Lerxst" contains "xs"
// gotXs : Boolean = true
val gotAb = "Lerxst" contains "Ab"
// gotAb : Boolean = false

Because a String is also a sequence, Scala extends String with containsSlice if you prefer (perhaps for idiomatic reasons) to use it instead of contains. It can take a String or a sequence of Chars:

val gotXs = "Lerxst" containsSlice "xs"
// gotXs : Boolean = true
val gotXs = "Lerxst" containsSlice Seq('x', 's')
// gotXs : Boolean = true

Maps

Map has a contains method, and it operates on the Map‘s keys, not its values or its key-value pairs:

val rushM = Map(
  "Dirk" -> "bass",
  "Lerxst" -> "guitar",
  "Pratt" -> "drums")
val gotGed = rushM contains "Dirk"
// val gotGed : bool = true

To look among a Map‘s values, get the valuesIterator first. I’m not wild about this interface. It should have been values instead, but values returns an Iterable, which has no contains method:

val gotDrummer = rushM.valuesIterator contains "drums"
// gotDrummer: Boolean = true
val gotSitarist = rushM.valuesIterator contains "sitar"
// gotSitarist: Boolean = false

There is no contains variant that searches on a key-value pair. You can define an extension method containsPair:

object MapExt {
  implicit class RichMap[A,B](val m: Map[A,B]) extends AnyVal {
    def containsPair(p: (A,B)): Boolean =
      m get p._1 contains p._2
  }
}

import MapExt._

val gotGedOnBass = rushM containsPair ("Dirk" -> "bass")
// gotGedOnBass: Boolean = true

val gotGedOnFlute = rushM containsPair ("Dirk" -> "flute")
// gotGedOnFlute: Boolean = false

val gotGeorgeOnSitar = rushM containsPair ("George" -> "sitar")
// gotGeorgeOnSitar: Boolean = false

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.