Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the index of an item in a SortedSet

I am implementing some kind of "record matrix" where the axis indices are (unique) keys of some type K (eg. String). These keys doesn't need to be sorted but I need an order, so I went for a SortedSet.

The main purpose of the keys (SortedSet) are to find the actual integer index in the underlying 2 dimensional data array (Seq[Seq[.]] or what ever). But I cannot find a ways to get such a f(key: K): Int function.

Instead of a SortedSet[K], I could use a Map[K,Int] which values are the indices, but I find that overkill (and not well typed).

Any idea?

Edit

The Map method is something like, but in 2D:

val myKeys = // SortedSet("A", "B", "C")
val data   = // Array(13,42,117)
val keyIndices = myKeys.zipWithIndex.toMap

// get indices of "B", and lookup in data array
data(keyIndices("B"))

I wrote "not well typed" for the Map solution because the type does not guaranty the indices are consecutive and starting at 0. While the position in an ordered seq is.

Selected solution

I selected Neumann's answer because it was best for my actual problem. But Cipcigan's and Verkerk's answers suits more the title.

like image 263
Juh_ Avatar asked Oct 21 '25 01:10

Juh_


2 Answers

Using zipWithIndex should do it:

def getIndex[T](xs: scala.collection.SortedSet[T], x:T): Option[Int] =
   xs.zipWithIndex.find(_._1 == x).map(_._2)

val a = scala.collection.SortedSet("a", "l", "m", "o", "n", "d")

getIndex(a, "a") // => Some(0)
getIndex(a, "m") // => Some(3)
getIndex(a, "x") // => None
like image 113
Flaviu Cipcigan Avatar answered Oct 23 '25 00:10

Flaviu Cipcigan


Short answer

Keeping theSet you can not. Having a way to get an element by index is a trait of a Seq.

scala> val data =scala.collection.SortedSet("a", "l", "m", "o", "n", "d")
data: scala.collection.SortedSet[String] = TreeSet(a, d, l, m, n, o)

scala> data(1)
<console>:12: error: type mismatch;
found   : Int(1)
required: String
   data(1)
        ^

scala> data("a")
res3: Boolean = true

I this example it is shown that the apply method checks if given argument is contained in the set.

I would go with the approach you already suggested by using the Map. Or transform the data to a Seq

scala> val indexedData = data.toVector
indexedData: Vector[String] = Vector(a, d, l, m, n, o)

scala> indexedData(2)
res9: String = l

scala> indexedData.indexOf("l")
res1: Int = 2
like image 37
Andreas Neumann Avatar answered Oct 22 '25 23:10

Andreas Neumann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!