Related
How to write shortly in Scala "filter out first/last n elements of a sequence satisfying a given function"?
FilterNot is defined:
def filterNot(p: A => Boolean): Repr
So I'm looking for function like:
def filterNotFirst(p: A => Boolean, n: Int): Repr
Preferably so that too big n does not throw exception.
The Scala collections library doesn't provide an operation that does exactly this, but there is an idiomatic way to write it: combine filter or filterNot and take or takeRight:
scala> val elems: Seq[Int] = 0 to 100
elems: Seq[Int] = Range 0 to 100
scala> elems.filterNot(_ < 10).take(5)
res0: Seq[Int] = Vector(10, 11, 12, 13, 14)
scala> elems.filterNot(_ < 10).takeRight(5)
res1: Seq[Int] = Vector(96, 97, 98, 99, 100)
This won't throw exceptions if n is larger than the number of available values:
scala> (0 to 15).filterNot(_ < 10).take(100)
res3: IndexedSeq[Int] = Vector(10, 11, 12, 13, 14, 15)
If you really want filterNotFirst as a method, you can define it yourself:
def filterNotFirst[A](elems: Seq[A])(p: A => Boolean, n: Int): Seq[A] =
elems.filterNot(p).take(n)
Or even:
scala> implicit class FilterNotFirstOp[A](elems: Seq[A]) {
| def filterNotFirst(p: A => Boolean, n: Int): Seq[A] =
| elems.filterNot(p).take(n)
| }
defined class FilterNotFirstOp
And then:
scala> (0 to 15).filterNotFirst(_ < 10, 100)
res4: Seq[Int] = Vector(10, 11, 12, 13, 14, 15)
I'd suggest just using filterNot and take where needed, though.
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 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'm looking to fold over the collection, I'm wondering if there is a more idiomatic approach. A recursive approach would allow me to avoid any vars. But basically, I'm wondering if something like the following is possible:
seq.rotatedView(i)
Which would create a rotated view, like rotating bits (or circular shift).
Is it like below:
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)
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).
Following the OP's comment that they want to fold over it, here's a slightly different take on it that avoids calculating the length of the sequence first.
Define an iterator that will iterate over the rotated sequence
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
}
And use it like this:
val seq = List(1, 2, 3, 4, 5)
val xs = new RotatedIterator(seq, 2)
println(xs.toList) //> List(3, 4, 5, 1, 2)
A simple method is to concatenate the sequence with itself and then take the slice that is required:
(seq ++ seq).slice(start, start + seq.length)
This is just a variant of the drop/take version but perhaps a little clearer.
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)
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.
It's not efficient
Another tail-recursive approach. When I benchmarked it with JMH it was about 2 times faster than solution based on drop/take:
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)
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)
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)
We can simply use foldLeft to reverse a list as below.
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)
Another one line solution if you don't need to validate the "offset":
def rotate[T](seq: Seq[T], offset: Int): Seq[T] = Seq(seq, seq).flatten.slice(offset, offset + seq.size)
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)
The following is an imperative solution to a simulation of a Number Lottery from the Range 1 to 45, each time we generate a number n1 the number is removed from the set of possible numbers.
Is it possible to achieve the same in a more functional way ? i.e using map,filter etc
def getNumbers :Array[Int] = {
val range = 1 to 45
var set = range.toSet
var resultSet:Set[Int] = Set()
var current: Int = 0
while(resultSet.size < 5 ){
current = Random.shuffle(set).head // pick the head of the shuffled set
set -= current
resultSet += current
}
resultSet.toArray
}
"edit"
An example pick 3 numbers from the Range 1 to 5
Original Set is {1,2,3,4,5}
{1,2,3,4,5} shuffle(1) picked at random 3
{1,2,4,5} shuffle(2) picked at random 2
{1,4,5} shuffle(3) picked at random 4
original Set becomes {1,5}
numbers picked {3,2,4}
each shuffle randomizes a different SET ! => different probabilities
I would like to see a functional "method" with 5 shuffles not 1 shuffle !
Sure, it's possible. The collections API has everything you need. What you're looking for is take, which will take the first n elements of the collection, or as many elements as the collection has if there are less than n.
Random.shuffle(1 to 45).take(5).toArray
I am with m-z on this, however if you REALLY want the functional form of a constant reshuffle, then you want something like this:
import scala.util.Random
import scala.annotation.tailrec
val initialSet = 1 to 45
def lottery(initialSet: Seq[Int], numbersPicked: Int): Set[Int] = {
#tailrec
def internalTailRec(setToUse: Seq[Int], picksLeft: Int, selection: Set[Int]):Set[Int]= {
if(picksLeft == 0) selection
else {
val selected = Random.shuffle(setToUse).head
internalTailRec(setToUse.filter(_ != selected), picksLeft - 1, selection ++ Set(selected))
}
}
internalTailRec(initialSet, numbersPicked, Set())
}
lottery(initialSet, 5)
This would simulate the behaviour you wanted:
Draw one, reshuffle data left, draw one and so on.
import scala.util.Random
import scala.annotation.tailrec
def draw(count: Int, data: Set[Int]): Set[Int] = {
#tailrec
def drawRec( accum: Set[Int] ) : Set[Int] =
if (accum.size == count )
accum
else
drawRec( accum + Random.shuffle( (data -- accum).toList ).head )
drawRec( Set() )
}
Example
scala> draw(5, (1 to 45).toSet)
res15: Set[Int] = Set(1, 41, 45, 17, 22)
scala> draw(5, (1 to 45).toSet)
res16: Set[Int] = Set(5, 24, 1, 6, 28)
I prefer #m-z's solution as well and agree with his reasoning about the probability. Reading the source for Random.shuffle is probably a worth while exercise.
Each iteration removes an element from range and adds it to the accumulator acc which is similar to your imperative approach except that we are not mutating collections and counters.
import scala.util.Random._
import scala.annotation.tailrec
def getNumbers(): Array[Int] = {
val range = (1 to 45).toSeq
#tailrec
def getNumbersR(range: Seq[Int], acc: Array[Int], i: Int): Array[Int] = (i, range(nextInt(range.size))) match{
case (i, x) if i < 5 => getNumbersR(range.filter(_ != x), x +: acc, i + 1)
case (i, x) => acc
}
getNumbersR(range, Array[Int](), 0)
}
scala> getNumbers
res78: Array[Int] = Array(4, 36, 41, 20, 14)
Is there a Round Robin Queue available in Scala Collections?
I need to repeatedly iterate a list that circles through itself
val x = new CircularList(1,2,3,4)
x.next (returns 1)
x.next (returns 2)
x.next (returns 3)
x.next (returns 4)
x.next (returns 1)
x.next (returns 2)
x.next (returns 3)
... and so on
It's pretty easy to roll your own with continually and flatten:
scala> val circular = Iterator.continually(List(1, 2, 3, 4)).flatten
circular: Iterator[Int] = non-empty iterator
scala> circular.take(17).mkString(" ")
res0: String = 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4
There's also a continually method on Stream—just be careful not to hold onto a reference to the head of the stream if you're going to be generating lots of elements.
You can very easily create a circular list using a Stream.
scala> val l = List(1, 2, 3, 4).toStream
l: scala.collection.immutable.Stream[Int] = Stream(1, ?)
scala> def b: Stream[Int] = l #::: b
b: Stream[Int]
scala> b.take(20).toList
res2: List[Int] = List(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)
Edit: you want to make sure to define the repeated part beforehand, once and only once, to avoid blowing the heap (structural sharing in Stream). As in:
def circular[A](a: Seq[A]): Stream[A] = {
val repeat = a.toStream
def b: Stream[A] = repeat #::: b
b
}
Version more concentrated on getting new element on every execution.
val getNext: () => Int = {
def b: Stream[Int] = List(1, 2, 3, 4).toStream #::: b
var cyclicIterator: Stream[Int] = b
() => {
val tail = cyclicIterator.tail
val result = tail.head
cyclicIterator = tail
result
}
} // could be written more sexy?
In your problem you can use it like:
for(i <- 1 to 10) yield getNext()
This is ugly in having an external mutable index, but it does do what's requested:
scala> var i = 0
scala> val ic4 = Iterator.continually { val next = IndexedSeq(1, 2, 3, 4)(i % 4); i += 1; next }
i: Int = 0
ic4: Iterator[Int] = non-empty iterator
scala> ic4 take 10 foreach { i => printf("ic4.next=%d%n", i) }
ic4.next=1
ic4.next=2
ic4.next=3
ic4.next=4
ic4.next=1
ic4.next=2
ic4.next=3
ic4.next=4
ic4.next=1
ic4.next=2
At least it illustrates Iterator.continually. There is also Stream.continually, which has the same signature.
This question already has answers here:
What is the fastest way to write Fibonacci function in Scala?
(8 answers)
Closed 5 years ago.
def fibSeq(n: Int): List[Int] = {
var ret = scala.collection.mutable.ListBuffer[Int](1, 2)
while (ret(ret.length - 1) < n) {
val temp = ret(ret.length - 1) + ret(ret.length - 2)
if (temp >= n) {
return ret.toList
}
ret += temp
}
ret.toList
}
So the above is my code to generate a Fibonacci sequence using Scala to a value n. I am wondering if there is a more elegant way to do this in Scala?
This is a bit more elegant:
val fibs: Stream[Int] = 0 #:: fibs.scanLeft(1)(_ + _)
With Streams you "take" a number of values, which you can then turn into a List:
scala> fibs take 10 toList
res42: List[Int] = List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
Update: I've written a blog post which goes more detail regarding how this solution works, and why you end up with a Fibonacci sequence!
There are many ways to define the Fibonacci sequence, but my favorite is this one:
val fibs:Stream[Int] = 0 #:: 1 #:: (fibs zip fibs.tail).map{ t => t._1 + t._2 }
This creates a stream that is evaluated lazily when you want a specific Fibonacci number.
EDIT:
First, as Luigi Plinge pointed out, the "lazy" at the beginning was unnecessary.
Second, go look at his answer, he pretty much did the same thing only more elegantly.
Not as elegant as Streams, not lazy, but tailrecursive and handles BigInt (which is easy to do with Luigis scanLeft too, but not so with Tal's zip - maybe just for me).
#tailrec
def fib (cnt: Int, low: BigInt=0, high: BigInt=1, sofar: List[BigInt]=Nil): List[BigInt] = {
if (cnt == 0) (low :: sofar).reverse else fib (cnt - 1, high, low + high, low :: sofar) }
scala> fib (75)
res135: List[BigInt] = List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049, 12586269025, 20365011074, 32951280099, 53316291173, 86267571272, 139583862445, 225851433717, 365435296162, 591286729879, 956722026041, 1548008755920, 2504730781961, 4052739537881, 6557470319842, 10610209857723, 17167680177565, 27777890035288, 44945570212853, 72723460248141, 117669030460994, 190392490709135, 308061521170129, 498454011879264, 806515533049393, 1304969544928657, 2111485077978050)
My favorite version is:
def fibs(a: Int = 0, b: Int = 1): Stream[Int] = Stream.cons(a, fibs(b, a+b))
With the default values you can just call fibs() and get the infinite Stream.
I also think it's highly readable despite being a one liner.
If you just want the first n then you can use take like fibs() take n, and if you need it as a list fibs() take n toList.
Here's yet another approach again using *Stream*s on an intermediary tuples:
scala> val fibs = Stream.iterate( (0,1) ) { case (a,b)=>(b,a+b) }.map(_._1)
fibs: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> fibs take 10 toList
res68: List[Int] = List(0, 1, 1, 2, 3, 5, 8, 13, 21, 34)
I find this implementation to be more legible:
def fibonacci: Stream[Int] = {
def loop(a: Int, b: Int): Stream[Int] = (a + b) #:: loop(b, b + a)
loop(0, 1)
}
def fib:Stream[Int] ={
def go(f0: Int, f1:Int): Stream[Int] = {
Stream.cons(f0,go(f1,f0+f1))
}
go(0,1)
}