How do you rotate (circular shift) the Scala collection

I can do this quite easily and cleanly using the for loop. For example, if I wanted to go Seqfrom each element back to myself, I would do the following:

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

for (i <- seq.indices) {
    for (j <- seq.indices) {
        print(seq(i + j % seq.length))
    }
}

But as I search foldthrough the collection, I wonder if there is a more idiomatic approach. A recursive approach would allow me to avoid any vars. But basically, I am wondering if something like the following is possible:

seq.rotatedView(i)

Which would create a rotated representation, such as rotating bits (or circular displacement).

+6
source share
9 answers

OP, , , .

,

class RotatedIterator[A](seq: Seq[A], start: Int) extends Iterator[A] {
  var (before, after) = seq.splitAt(start)
  def next = after match {
    case Seq()  =>
      val (h :: t) = before; before = t; h
    case h :: t => after = t; h
  }
  def hasNext = after.nonEmpty || before.nonEmpty
}

:

val seq = List(1, 2, 3, 4, 5)  
val xs = new RotatedIterator(seq, 2)
println(xs.toList)         //> List(3, 4, 5, 1, 2)
+5

:

scala> def rotatedView(i:Int)=Seq(1,2,3,4,5).drop(i)++Seq(1,2,3,4,5).take(i)
rotatedView: (i: Int)Seq[Int]

scala> rotatedView(1)
res48: Seq[Int] = List(2, 3, 4, 5, 1)

scala> rotatedView(2)
res49: Seq[Int] = List(3, 4, 5, 1, 2)
+16

:

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))
}

, , drop i , take - , . , , i .

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)

, 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
}

, :

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, ?)

, , , ( ).

+6

:

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

:

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

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

:

List(4, 5, 1, 2, 3)
  • , , rotation%length, , (rotation+1)%length .
+2

liner

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

Scala:

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

foldLeft , foldLeft .

  val input = List(1,2,3,4,5)

  val res = input.foldLeft(List[Int]())((s, a) => { List(a) ++: s})

  println(res) // List(5, 4, 3, 2, 1)
0

Another tail-recursive approach. When I compared it with JMH, it was about 2 times faster than the drop / back based solution :

def rotate[A](list: List[A], by: Int): List[A] = {

    @tailrec
    def go(list: List[A], n: Int, acc: List[A]): List[A] = {

      if(n > 0) {
        list match {
          case x :: xs => go(xs, n-1, x :: acc)
        }
      } else {
        list ++ acc.reverse
      }

    }

    if (by < 0) {
      go(list, -by % list.length, Nil)
    } else {
      go(list, list.length - by % list.length, Nil)
    }    
}

//rotate right
rotate(List(1,2,3,4,5,6,7,8,9,10), 3) // List(8, 9, 10, 1, 2, 3, 4, 5, 6, 7) 

//use negative number to rotate left
rotate(List(1,2,3,4,5,6,7,8,9,10), -3) // List(4, 5, 6, 7, 8, 9, 10, 1, 2, 3)
0
source

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 further processing 0 ArrayBuffer (2, 3, 4, 5, 6, 1)

for the subsequent process 1 ArrayBuffer (3, 4, 5, 6, 1, 2)

for the subsequent process 2 ArrayBuffer (4, 5, 6, 1, 2, 3)

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

0
source

Source: https://habr.com/ru/post/1608391/


All Articles