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 g
Not much clear, but still:
xs.indices.collect { case i if i % 3 == 0 => xs(i) }
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
}
Ah, how about this?
val l = List(10,9,8,7,6,5,4,3,2,1,0)
for (i <- (0 to l.size - 1 by 3).toList) yield l(i)
//res0: List[Int] = List(10, 7, 4, 1)
which can be made more general by
def seqByN[A](xs: Seq[A], n: Int): Seq[A] = for (i <- 0 to xs.size - 1 by n) yield xs(i)
scala> seqByN(List(10,9,8,7,6,5,4,3,2,1,0), 3)
res1: Seq[Int] = Vector(10,7,4,1)
scala> seqByN(List(10,9,8,7,6,5,4,3,2,1,0), 3).toList
res2: Seq[Int] = List(10,7,4,1)
scala> seqByN(List[Int](), 3)
res1: Seq[Int] = Vector()
But by functional do you mean only using the various List combinator functions? Otherwise, are Streams functional enough?
def fromByN[A](xs: List[A], n: Int): Stream[A] = if (xs.isEmpty) Stream.empty else
xs.head #:: fromByN(xs drop n, n)
scala> fromByN(List(10,9,8,7,6,5,4,3,2,1,0), 3).toList
res17: List[Int] = List(10, 7, 4, 1)
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
}
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.
I would do it like in Octave mathematical program.
val indices = 0 until n by 3 // Range 0,3,6,9 ...
and then I needed some way to select the indices from a collection. Obviously I had to have a collection with random-access O(1). Like Array
or Vector
. For example here I use Vector
. To wrap the access into a nice DSL I'd add an implicit class:
implicit class VectorEnrichedWithIndices[T](v:Vector[T]) {
def apply(indices:TraversableOnce[Int]):Vector[T] = {
// some implementation
indices.toVector.map(v)
}
}
The usage would look like:
val vector = list.toVector
val every3rdElement = vector(0 until vector.size by 3)