Question: Starting from a sorted sequence of values, my goal is to assign a rank to each value, using identical ranks for equal values (aka ties):

Input: `Vector(1, 1, 3, 3, 3, 5, 6)`

Output: `Vector((0,1), (0,1), (1,3), (1,3), (1,3), (2,5), (3,6))`

A few type aliases for readability:

```
type Rank = Int
type Value = Int
type RankValuePair = (Rank, Value)

```

An imperative implementation using a mutable `rank` variable could look like this:

```
var rank = 0
val ranked1: Vector[RankValuePair] = for ((value, index) <- values.zipWithIndex) yield {
  if ((index > 0) && (values(index - 1) != value)) rank += 1
  (rank, value)
}

// ranked1: Vector((0,1), (0,1), (1,3), (1,3), (1,3), (2,5), (3,6))

```

To hone my FP skills, I was trying to come up with a functional implementation:

```
val ranked2: Vector[RankValuePair] = values.sliding(2).foldLeft((0 , Vector.empty[RankValuePair])) {
  case ((rank: Rank, rankedValues: Vector[RankValuePair]), Vector(currentValue, nextValue)) =>
    val newRank = if (nextValue > currentValue) rank + 1 else rank
    val newRankedValues =  rankedValues :+ (rank, currentValue)
    (newRank, newRankedValues)
}._2

// ranked2: Vector((0,1), (0,1), (1,3), (1,3), (1,3), (2,5))

```

It is less readable, and – more importantly – is missing the last value (due to using `sliding(2)` on an odd number of values).

How could this be fixed and improved?

Answer: 
This is a modification of the solution by @jwvh, that doesn't make any assumptions about the values:

```
val vs = Vector(1, 1, 3, 3, 3, 5, 6)
vs.sliding(2).scanLeft(0, vs.head) {
  case ((rank, _), Seq(a, b)) => (if (a != b) rank + 1 else rank, b)
}.toVector

```

Note, that it would throw if `vs` is empty, so you'd have to use `vs.headOption getOrElse 0`, or check if the input is empty beforehand: `if (vs.isEmpty) Vector.empty else ...`
```
import scala.annotation.tailrec

type Rank = Int
// defined type alias Rank
type Value = Int
// defined type alias Value
type RankValuePair = (Rank, Value)
// defined type alias RankValuePair

def rankThem(values: List[Value]): List[RankValuePair] = {

  // Assumes that the "values" are sorted
  @tailrec
  def _rankThem(currentRank: Rank, currentValue: Value, ranked: List[RankValuePair], values: List[Value]): List[RankValuePair] = values match {
    case value :: tail if value == currentValue => _rankThem(currentRank, value, (currentRank, value) +: ranked, tail)
    case value :: tail if value > currentValue => _rankThem(currentRank + 1, value, (currentRank + 1, value) +: ranked, tail)
    case Nil => ranked.reverse
  }

  _rankThem(0, Int.MinValue, List.empty[RankValuePair], values.sorted)
}
// rankThem: rankThem[](val values: List[Value]) => List[RankValuePair]

val valueList = List(1, 1, 3, 3, 5, 6)
// valueList: List[Int] = List(1, 1, 3, 3, 5, 6)

val rankValueList = rankThem(valueList)[RankedValuePair], values: Vector[Value])
// rankValueList: List[RankValuePair] = List((1,1), (1,1), (2,3), (2,3), (3,5), (4,6))

```