How do you rotate (circular shift) of a Scala collection

后端 未结 11 1505
盖世英雄少女心
盖世英雄少女心 2020-12-19 03:40

I can do this quite easily, and cleanly, using a for loop. For instance, if I wanted to traverse a Seq from every element back to itself I would do the

相关标签:
11条回答
  • 2020-12-19 04:15

    Here's a fairly simple and idiomatic Scala collections way to write it:

    def rotateSeq[A](seq: Seq[A], isLeft: Boolean = false, count: Int = 1): Seq[A] =
      if (isLeft)
        seq.drop(count) ++ seq.take(count)
      else
        seq.takeRight(count) ++ seq.dropRight(count)
    
    0 讨论(0)
  • 2020-12-19 04:16

    Given:

    val seq = Seq(1,2,3,4,5)
    

    Solution:

    seq.zipWithIndex.groupBy(_._2<3).values.flatMap(_.map(_._1))
    

    or

    seq.zipWithIndex.groupBy(_._2<3).values.flatten.map(_._1)
    

    Result:

    List(4, 5, 1, 2, 3)
    
    1. If rotation is more than length of collection - we need to use rotation%length, if negative than formula (rotation+1)%length and take absolute value.
    2. It's not efficient
    0 讨论(0)
  • 2020-12-19 04:16

    This is a simple piece of code

      object tesing_it extends App 
    {
    val one = ArrayBuffer(1,2,3,4,5,6)
    val  i = 2  //the number of index you want to move
    
    
    
     for(z<-0 to i){
       val y = 0
       var x =  one += one(y)
       x = x -= x(y)
       println("for seq after process " +z +" " + x)
      }
    
    
    println(one)
    
    }
    

    Result:

    for seq after process 0 ArrayBuffer(2, 3, 4, 5, 6, 1)

    for seq after process 1 ArrayBuffer(3, 4, 5, 6, 1, 2)

    for seq after process 2 ArrayBuffer(4, 5, 6, 1, 2, 3)

    ArrayBuffer(4, 5, 6, 1, 2, 3)

    0 讨论(0)
  • 2020-12-19 04:19

    This ought to do it in a fairly generic way, and allow for arbitrary rotations:

    def rotateLeft[A](seq: Seq[A], i: Int): Seq[A] = {
        val size = seq.size
        seq.drop(i % size) ++ seq.take(i % size)
    }
    
    def rotateRight[A](seq: Seq[A], i: Int): Seq[A] = {
        val size = seq.size
        seq.drop(size - (i % size)) ++ seq.take(size - (i % size))
    }
    

    The idea is simple enough, to rotate left, drop the first i elements from the left, and take them again from the left to concatenate them in the opposite order. If you don't mind calculating the size of the collection, you can do your operations modulo the size, to allow i to be arbitrary.

    scala> rotateRight(seq, 1)
    res34: Seq[Int] = List(5, 1, 2, 3, 4)
    
    scala> rotateRight(seq, 7)
    res35: Seq[Int] = List(4, 5, 1, 2, 3)
    
    scala> rotateRight(seq, 70)
    res36: Seq[Int] = List(1, 2, 3, 4, 5)
    

    Similarly, you can use splitAt:

    def rotateLeft[A](seq: Seq[A], i: Int): Seq[A] = {
        val size = seq.size
        val (first, last) = seq.splitAt(i % size)
        last ++ first
    }
    
    def rotateRight[A](seq: Seq[A], i: Int): Seq[A] = {
        val size = seq.size
        val (first, last) = seq.splitAt(size - (i % size))
        last ++ first
    }
    

    To make it even more generic, using the enrich my library pattern:

    import scala.collection.TraversableLike
    import scala.collection.generic.CanBuildFrom
    
    implicit class TraversableExt[A, Repr <: TraversableLike[A, Repr]](xs: TraversableLike[A, Repr]) {
    
        def rotateLeft(i: Int)(implicit cbf: CanBuildFrom[Repr, A, Repr]): Repr = {
            val size = xs.size
            val (first, last) = xs.splitAt(i % size)
            last ++ first
        }
    
        def rotateRight(i: Int)(implicit cbf: CanBuildFrom[Repr, A, Repr]): Repr = {
            val size = xs.size
            val (first, last) = xs.splitAt(size - (i % size))
            last ++ first
        }
    
    }
    
    scala> Seq(1, 2, 3, 4, 5).rotateRight(2)
    res0: Seq[Int] = List(4, 5, 1, 2, 3)
    
    scala> List(1, 2, 3, 4, 5).rotateLeft(2)
    res1: List[Int] = List(3, 4, 5, 1, 2)
    
    scala> Stream(1, 2, 3, 4, 5).rotateRight(1)
    res2: scala.collection.immutable.Stream[Int] = Stream(5, ?)
    

    Keep in mind these are not all necessarily the most tuned for performance, and they also can't work with infinite collections (none can).

    0 讨论(0)
  • 2020-12-19 04:21

    Here is one liner solution

    def rotateRight(A: Array[Int], K: Int): Array[Int] = {
        if (null == A || A.size == 0) A else (A drop A.size - (K % A.size)) ++ (A take A.size - (K % A.size))
    }
    rotateRight(Array(1,2,3,4,5), 3)
    
    0 讨论(0)
提交回复
热议问题