Scala filter on a list by index

11,257

Solution 1

If efficiency is not an issue, you could do the following:

list.grouped(3).map(_.head)

Note that this constructs intermediate lists.

Alternatively you can use a for-comprehension:

for {
  (x,i) <- list zipWithIndex
  if i % 3 == 0
} yield x

This is of course almost identical to your original solution, just written differently.

My last alternative for you is the use of collect on the zipped list:

list.zipWithIndex.collect {
  case (x,i) if i % 3 == 0 => x
}

Solution 2

Not much clear, but still:

xs.indices.collect { case i if i % 3 == 0 => xs(i) }

Solution 3

A nice, functional solution, without creating temporary vectors, lists, and so on:

def everyNth[T](xs: List[T], n:Int): List[T] = xs match {
  case hd::tl => hd::everyNth(tl.drop(n-1), n)
  case Nil => Nil
}

Solution 4

Clojure has a take-nth function that does what you want, but I was surprised to find that there's not an equivalent method in Scala. You could code up a similar recursive solution based off the Clojure code, or you could read this blog post:

Scala collections: Filtering each n-th element

The author actually has a nice graph at the end showing the relative performance of each of his solutions.

Share:
11,257
user833970
Author by

user833970

Updated on June 04, 2022

Comments

  • user833970
    user833970 almost 2 years

    I wanted to write it functionally, and the best I could do was:

    list.zipWithIndex.filter((tt:Tuple2[Thing,Int])=>(tt._2%3==0)).unzip._1
    

    to get elements 0, 3, 6,...

    Is there a more readable Scala idiom for this?

  • gzm0
    gzm0 over 10 years
    You might want to add that indexed access should be O(1), otherwise this will not perform O(n).