Dark
Dark

Reputation: 803

Get value with the lowest key value from Map[Int, String]

Say I have a map: Map[Int, String]. How would I get the value [String] with the lowest key [Int]. I've been trying to implement this functionally, but just can't figure out how to do this.

Upvotes: 3

Views: 1170

Answers (4)

stefan.schwetschke
stefan.schwetschke

Reputation: 8932

A variant of the _.keys.min solution that works with Options (i.e. will not throw on an empty map):

scala> val a : Map[Int, String]=Map(1 -> "1", 2 -> "2")
a: Map[Int,String] = Map(1 -> 1, 2 -> 2)

scala> val b : Map[Int, String]=Map()
b: Map[Int,String] = Map()

scala> def valueForMinKey[K,V](a : Map[K,V])(implicit cmp : Ordering[K]) = a.keys.reduceOption(cmp.min(_, _)).map(a(_))
valueForMinKey: [K, V](a: Map[K,V])(implicit cmp: Ordering[K])Option[V]

scala> valueForMinKey(a)
res27: Option[String] = Some(1)

scala> valueForMinKey(b)
res28: Option[String] = None

In this example, the implicit parameter cmp will be satisfied by Ordering.Int. The example will work with any Map where the keys can be ordered (and a matching implict can be found by the compiler).

Upvotes: 2

som-snytt
som-snytt

Reputation: 39577

Come on, people! "Functionally" is code word for "folding".

scala> val m = Map(1->"eins",2->"zwei",3->"drei")
m: scala.collection.immutable.Map[Int,String] = Map(1 -> eins, 2 -> zwei, 3 -> drei)

scala> m.foldLeft(Int.MaxValue -> "") { case (min,p) => if (min._1 <= p._1) min else p }
res0: (Int, String) = (1,eins)

But an 8-char operator?

Let's see, is that enough parens? Don't tell me -> is like - and /: is like /.

scala> (Int.MaxValue -> "" /: m) { case (min,p) => if (min._1 <= p._1) min else p }
<console>:9: error: missing arguments for method /: in trait TraversableOnce;
follow this method with `_' if you want to treat it as a partially applied function
              (Int.MaxValue -> "" /: m) { case (min,p) => if (min._1 <= p._1) min else p }
                                  ^

Oh, well, OK.

scala> ((Int.MaxValue -> "") /: m) { case (min,p) => if (min._1 <= p._1) min else p }
res2: (Int, String) = (1,eins)

Or,

scala> import math.Ordering.Implicits._
import math.Ordering.Implicits._

scala> ((Int.MaxValue -> "") /: m) { case (min,p) if min <= p => min case (_, p) => p }
res5: (Int, String) = (1,eins)

Upvotes: 2

ziggystar
ziggystar

Reputation: 28688

The following code will get you a value with a lowest key (ignoring some corner cases).

def lowestKeyMember[A](m: Map[Int,A]): A = m(m.keys.min)

This will break ties arbitrarily and throw on an empty map. If you need to do this operation frequently and/or on large maps, you should look into SortedMap.

Upvotes: 4

Nick Humrich
Nick Humrich

Reputation: 15755

Maps are not normally sorted. You could however use a SortedMap, then the map will be sorted and the first value will be the head. All you need to do is retrieve the head.

map.head()

Upvotes: 2

Related Questions