3

I would like to refactor this piece of Scala code in functional style:

var k = -1
for (i <- 0 until array.length)
  if ((i < array.length - 1) && array(i) < array(i + 1))
    k = i

Array in Scala has indexWhere, which can be used for something like val index = array.indexWhere(c => c == 'a'). I'm looking for something similar, which would take into account two sequential elements of array.

2 Answers 2

17

When you need to look at adjacent elements in a collection, the usual functional approach is to "zip" the collection with its tail. Consider the following simplified example:

scala> val xs = List(5, 4, 2, 3, 1)
xs: List[Int] = List(5, 4, 2, 3, 1)

scala> val tail = xs.tail
tail: List[Int] = List(4, 2, 3, 1)

scala> xs.zip(tail)
res0: List[(Int, Int)] = List((5,4), (4,2), (2,3), (3,1)

Now we can use indexWhere:

scala> res0.indexWhere { case (x, y) => x < y }
res1: Int = 2

In your case, the following is essentially equivalent to your code:

val k = (array zip array.tail) lastIndexWhere { case (x, y) => x < y }

I'm using lastIndexWhere instead of indexWhere, since in your code you don't stop the loop when you hit a pair for which the predicate holds.

Sign up to request clarification or add additional context in comments.

Comments

11

sliding gives you sliding window into the collection, ie

scala> Array(1,2,2,4,5,6, 6).sliding(2).toList
res12: List[Array[Int]] = List(Array(1, 2), Array(2, 2), Array(2, 4), Array(4, 5), Array(5, 6), Array(6, 6))

So that would make finding the index of the first matching pair easy:

Array(1,2,2,4,5,6, 6).sliding(2).indexWhere { case Array(x1, x2) => x1 == x2 }

That only gives you the first index, use collect to catch em all!

Array(1,2,2,4,5,6, 6)
  .sliding(2)     //splits each in to pairs
  .zipWithIndex   //attaches the current index to each pair
  .collect { case (Array(x1, x2), index) if (x1 == x2) => index }  //collect filters out non-matching pairs AND transforms them to just the inde

1 Comment

I know it's a matter of taste, but the fact that the sliding approach gives you collections of length two (instead of tuples) makes it feel clunky here to me. Also, many (most?) functional language don't provide a sliding function in their standard collections API, while zip is pretty universal.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.