Scala filter on a list by index

前端 未结 6 1350
一整个雨季
一整个雨季 2021-02-15 12:52

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

相关标签:
6条回答
  • 2021-02-15 13:18

    Not much clear, but still:

    xs.indices.collect { case i if i % 3 == 0 => xs(i) }
    
    0 讨论(0)
  • 2021-02-15 13:21

    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
    }
    
    0 讨论(0)
  • 2021-02-15 13:24

    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)
    
    0 讨论(0)
  • 2021-02-15 13:25

    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
    }
    
    0 讨论(0)
  • 2021-02-15 13:25

    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.

    0 讨论(0)
  • 2021-02-15 13:29

    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)
    
    0 讨论(0)
提交回复
热议问题