2

I'm trying to write the get method for a key, value pair implemented using a list. I want to use the Option type as I heard its good for this but I'm new to Scala and I'm not really sure how to use it in this case...

This is as far as I got, only the method header.

def get(key : String): Option[Any] = {}
dbc
  • 104,963
  • 20
  • 228
  • 340
JrPtn
  • 83
  • 2
  • 8

3 Answers3

3

My guess is you are looking for something like this:

class KeyValueStore(pairs: List[(String, Any)]) {

  def get(key: String): Option[Any] = pairs.collectFirst {
    case (k, v) if k == key => v
  }

}

This uses the collectFirst method for sequences. If you want a more "do it yourself" approach, this should work:

def get(key: String): Option[Any] = {
  def search(xs: List[(String, Any)]): Option[Any] = {
    xs match {
      case List() => None //end of list and key not found. We return None
      case (k, v) :: rest if k == key => Some(v) // found our key. Returning some value
      case _ :: rest => search(rest) // not found until nou. Carrying on with the rest of the list
    }

    search(pairs)
  }
}
Marius Danila
  • 10,311
  • 2
  • 34
  • 37
  • When doing that I get a type mismatch error. It returns a List but needs an Option. – JrPtn Sep 24 '13 at 19:43
  • Sorry. It's `collectFirst`, not `collect`. I fixed my answer – Marius Danila Sep 24 '13 at 19:43
  • Thank you! That worked perfectly. One more thing, any tips for remove? I'm trying to use the same principles as get but I'm having trouble keeping the elements that don't equal key in the list. Example: If my list is ("A",1),("B",2"),("C",3),("D",4) and I wanted to remove C, how would I ensure A, B, D are still there? – JrPtn Sep 24 '13 at 20:05
  • @aepurniet's suggestion would work. Also, filterNot may be more intuitive: `pairs filterNot { _ == key }` – Marius Danila Sep 24 '13 at 20:33
  • I would have used `find`: `pairs.find(_._1 == k).map(_._2)`. I wonder if `collectFirst` is faster here? – scand1sk Sep 24 '13 at 21:19
  • I'm having a hard time using filter and filterNot. When I execute it, it doesn't seem to do anything to the list. Is there any other way? I'm trying to use Option on this as well. – JrPtn Sep 24 '13 at 23:26
  • I'm getting the feeling that you're expecting the `filter` method to modify the list. Lists in Scala are immutable, they can't be changed. What filter does is to create a new list that contains only the elements that meet the criteria. That's idiomatic Scala - we don't change things - we create new ones. It may seem strange at first, but it works really well in practice. I've prepared some examples about how to implement your class. One includes a remove method that actually removes the element from the collection.The second one takes the recommended, immutable way http://pastebin.com/w0TTwZZD – Marius Danila Sep 25 '13 at 08:09
0

You can turn a List of Pairs into a Map:

class Store[K, V](values: List[(K, V)]) {
  val map = values.toMap
  def get(key: K): Option[V] = map get key
}
Channing Walton
  • 3,977
  • 1
  • 30
  • 59
0

Although @Marius' collectFirst version is probably the most elegant (and maybe a little bit faster as it only uses one closure), I find it more intuitive to use find for your problem :

def get[A, B](key: A, pairs: List[(A, B)]): Option[B] = pairs.find(_._1 == key).map(_._2)

In case you were wondering (or need high performance), you will need either @Marius' recursive or the following imperative version which may look more familiar (although less idiomatic):

def get[A, B](key: A, pairs: List[(A, B)]): Option[B] = {
  var l = pairs
  var found: Option[B] = None
  while (l.nonEmpty && found.isEmpty) {
    val (k, v) = l.head
    if (k == key) {
      found = Some(v)
    } else {
      l = l.tail
    }
  }
  found
}

What you must understand is that Option[B] is a class that may either be instantiated to None (which replaces and improves the null reference used in other languages) or Some(value: B). Some is a case class, which allows, among other neat features, to instantiate it without the new keyword (thanks to some compiler magic, Google Scala case class for more info). You can think of Option as a List which may contain either 0 or 1 element: most operations that can be done on sequences can also be applied to Options (such as map in the find version).

scand1sk
  • 1,114
  • 11
  • 25