How can I achieve multiple step in scala range - scala

How can I achieve multiple step in scala range
Like this:
var r = 1 to 100 by (2, 3, 4)
And the last number 4, if there are more to step, will be the repeat step.
or bonus: something like with mode
1. var = 1 to 100 by (2, 3, 4) review // review steps from 2, 3, 4 again.
2. var = 1 to 100 by (2, 3, 4) last // use last number as final steps.
3. var = 1 to 100 by (2, 3, 4) random // use steps randomly within these numbers.
4. var = 1 to 100 by (2, 3, 4) reverse // use steps in reverse and reverse manner.

import scala.collection.immutable.Stream
import scala.collection.mutable.ListBuffer
import scala.util.Random
abstract class RangeX(override val head: Int, val end: Int, var step: Int) extends Stream[Int] {
override val tailDefined = false
override val isEmpty = head > end
def by(steps: Seq[Int]) = {
StepVariant(this, steps)
}
def byGroup(steps: Seq[Int]) = {
StepVariantInGroup(this, steps)
}
def steps(steps: Seq[Int])(fn_steps: (Seq[Int], Int) => Int) = {
var acc = new ListBuffer[Int]()
this.zipWithIndex.foreach {
case (i, idx) =>
acc += i
this.step = fn_steps(steps, idx)
}
acc.toList
}
def stepsByGroup(steps: Seq[Int])(fn_steps: (Seq[Int], Int) => Int) = {
val ls = this.steps(steps)(fn_steps)
var acc = new ListBuffer[List[Int]]()
val lidx = ls.length - 1
(1 to lidx).foreach { i =>
acc += (ls(i - 1) to ls(i) - 1).toList
}
acc.toList
}
case class StepVariant(streams: RangeX, steps: Seq[Int]) {
def repeating_steps = streams.steps(steps)(RangeX.repeating_steps)
def repeat_last_step = streams.steps(steps)(RangeX.repeat_last_step)
def random_steps = streams.steps(steps)(RangeX.random_steps)
def reversing_steps = streams.steps(steps)(RangeX.reversing_steps)
}
case class StepVariantInGroup(streams: RangeX, steps: Seq[Int]) {
def repeating_steps = streams.stepsByGroup(steps)(RangeX.repeating_steps)
def repeat_last_step = streams.stepsByGroup(steps)(RangeX.repeat_last_step)
def random_steps = streams.stepsByGroup(steps)(RangeX.random_steps)
def reversing_steps = streams.stepsByGroup(steps)(RangeX.reversing_steps)
}
}
class RangeSlaveX(_head: Int, _end: Int, _step: Int, val master: RangeX) extends RangeX(_head, _end, _step) {
override def tail = if (isEmpty) Stream.Empty else new RangeSlaveX(head + master.step, end, master.step, master)
}
class RangeMasterX(_head: Int, _end: Int, _step: Int) extends RangeX(_head, _end, _step) {
override def tail = if( isEmpty ) Stream.Empty else new RangeSlaveX(head + step, end, step, this)
}
object RangeX {
implicit def toRangeX(range: Range): RangeX = new RangeMasterX(range.start, range.end, range.step)
def apply(head: Int, end: Int, step: Int) = new RangeMasterX(head, end, step)
def repeating_steps(steps: Seq[Int], idx: Int): Int = {
val size = steps.size
steps( idx % size )
}
def repeat_last_step(steps: Seq[Int], idx: Int): Int = {
val len = steps.length - 1
steps(if( idx >= len) len else idx)
}
def random_steps(steps: Seq[Int], idx: Int): Int = {
Random.shuffle(steps).head
}
def reversing_steps(steps: Seq[Int], idx: Int): Int = {
val size = steps.size
val lidx = size - 1
val forward = ((idx / size) % 2) == 0
if(forward) {
steps( idx % size )
} else {
steps( lidx - (idx % size))
}
}
}
scala> import RangeX._
import RangeX._
Method Chaining Way: - by and byGroup
scala> 1 to 20 byGroup Seq(1, 2, 3) reversing_steps
res0: List[List[Int]] = List(List(1), List(2, 3), List(4, 5, 6), List(7, 8, 9), List(10, 11), List(12), List(13), List(14, 15), List(16, 17, 18))
scala> 1 to 20 byGroup Seq(1, 2, 3) random_steps
res1: List[List[Int]] = List(List(1, 2, 3), List(4, 5), List(6, 7, 8), List(9, 10), List(11, 12), List(13, 14, 15), List(16, 17, 18))
scala> 1 to 20 byGroup Seq(1, 2, 3) repeating_steps
res2: List[List[Int]] = List(List(1), List(2, 3), List(4, 5, 6), List(7), List(8, 9), List(10, 11, 12), List(13), List(14, 15), List(16, 17, 18), List(19))
scala> 1 to 20 byGroup Seq(1, 2, 3) repeat_last_step
res3: List[List[Int]] = List(List(1), List(2, 3), List(4, 5, 6), List(7, 8, 9), List(10, 11, 12), List(13, 14, 15), List(16, 17, 18))
scala> 1 to 20 by Seq(1, 2, 3) reversing_steps
res4: List[Int] = List(1, 2, 4, 7, 10, 12, 13, 14, 16, 19)
scala> 1 to 20 by Seq(1, 2, 3) random_steps
res5: List[Int] = List(1, 2, 3, 6, 8, 11, 13, 15, 17, 19, 20)
scala> 1 to 20 by Seq(1, 2, 3) repeating_steps
res6: List[Int] = List(1, 2, 4, 7, 8, 10, 13, 14, 16, 19, 20)
scala> 1 to 20 by Seq(1, 2, 3) repeat_last_step
res7: List[Int] = List(1, 2, 4, 7, 10, 13, 16, 19)
Functional Way: - steps and stepsByGroup
scala> (1 to 20).steps(Seq(1, 2, 3))(reversing_steps)
res12: List[Int] = List(1, 2, 4, 7, 10, 12, 13, 14, 16, 19)
scala> (1 to 20).steps(Seq(1, 2, 3))(random_steps)
res13: List[Int] = List(1, 4, 6, 8, 10, 12, 14, 16, 17, 18, 20)
scala> (1 to 20).steps(Seq(1, 2, 3))(repeating_steps)
res11: List[Int] = List(1, 2, 4, 7, 8, 10, 13, 14, 16, 19, 20)
scala> (1 to 20).steps(Seq(1, 2, 3))(repeat_last_step)
res15: List[Int] = List(1, 2, 4, 7, 10, 13, 16, 19)
scala> (1 to 20).stepsByGroup(Seq(1, 2, 3))(reversing_steps)
res17: List[List[Int]] = List(List(1), List(2, 3), List(4, 5, 6), List(7, 8, 9), List(10, 11), List(12), List(13), List(14, 15), List(16, 17, 18))
scala> (1 to 20).stepsByGroup(Seq(1, 2, 3))(random_steps)
res18: List[List[Int]] = List(List(1, 2), List(3, 4), List(5), List(6), List(7), List(8, 9), List(10, 11), List(12, 13), List(14, 15, 16), List(17, 18, 19))
scala> (1 to 20).stepsByGroup(Seq(1, 2, 3))(repeating_steps)
res19: List[List[Int]] = List(List(1), List(2, 3), List(4, 5, 6), List(7), List(8, 9), List(10, 11, 12), List(13), List(14, 15), List(16, 17, 18), List(19))
scala> (1 to 20).stepsByGroup(Seq(1, 2, 3))(repeat_last_step)
res20: List[List[Int]] = List(List(1), List(2, 3), List(4, 5, 6), List(7, 8, 9), List(10, 11, 12), List(13, 14, 15), List(16, 17, 18))
How's my revise implementation ^. Seed idea from #Piro implementation link. Thx.
Step Variants
review is repeating_steps
last is repeat_last_step
random is random_steps
reverse is reversing_steps
I wish Sir Martin Odersky add these kind of Range features by(Seq(1,2,3)) *_steps and byGroup(Seq(1,2,3)) *_steps in next Scala release :)

Related

Scala's List unpacking

So my problem is simple. I have come across this many times, and my brain is unable to find a solution.
How can I unpack a list into another list, for an indefinite amount of variables?
Here is what I mean.
val list1 = List(List(7, 4), List(7, 6))
val list2 = List(List(1), List(5), List(8))
val desired_list1 = List(List(1, 7, 4), List(5, 7, 4), List(8, 7, 4))
val desired_list2 = List(List(1, 7, 6), List(5, 7, 6), List(8, 7, 6))
//** The desired_list1 and 2 must be a List[List[Int]] it cannot be List[List[Any]]
//Here's my attempt, which oddly enough completely ignores all elements of list1(0) which are not the first(7).
val attempt = list2.map(i => i +: list1(0)).map(j => j.collect{ case k:Int => k; case l # a :: b => a}).map(m => m.map{ case i:Any => i.toString.toInt})
//The result is
attempt: List[List[Int]] = List(List(1, 7), List(5, 7), List(8, 7))
//while it should be:
val desired_list1 = List(List(1, 7, 4), List(5, 7, 4), List(8, 7, 4))
I need a way to unpack that is not manual, please do not tell me to do this:
val attempt = list2.map(k => k +: list1(0)).map{ case (k, List(x, y)) => (k, x, y)}
Basically, list1 could have any number of elements. e.g
val list1 = List(List(99, 83, 2, 3, 4), List(99, 83, 2, 5 7))
However, these numbers are never repeated, so I guess it could be a set as well. But I don't know much about sets or if it'd help in any way.
This seems to be what you want:
val lists: List[List[Int]] = List(List(7, 4), List(7, 6))
val prefixes: List[List[Int]] = List(List(1), List(5), List(8))
val res: List[List[Int]] = for{
prefix <- prefixes.flatten
rest <- lists
} yield prefix :: res
// res: List[List[Int]] = List(List(1, 7, 4), List(1, 7, 6), List(5, 7, 4), List(5, 7, 6), List(8, 7, 4), List(8, 7, 6))
Unless, you actually want a list that contains your desired_list1 and desired_list2 together, in which case you need:
val res3 = lists.map{ rest =>
prefixes.flatten.map{prefix =>
prefix :: rest
}
}
/// res3: List[List[List[Int]]] =
// List(
// List(
// List(1, 7, 4), List(5, 7, 4), List(8, 7, 4)
// ),
// List(
// List(1, 7, 6), List(5, 7, 6), List(8, 7, 6)
// )
// )
I am not sure exactly why you would want that but try this out:
val list1 = List(List(7, 4), List(7, 6))
val list2 = List(1, 5, 8)
list2.flatMap(element=> list1.map(innerList=> element:: innerList))
output: List[List[Int]] = List(List(1, 7, 4), List(1, 7, 6), List(5, 7, 4), List(5, 7, 6), List(8, 7, 4), List(8, 7, 6))

Finding all slices delimited by two elements in Scala `List`

In Scala, what would be the right way of selecting elements of a list based on the position of two elements? Suppose I have the list below and I would like to select all the elements between 2 and 7, including them (note: not greater than/smaller than, but the elements that come after 2 and before 7 in the list):
scala> val l = List(1, 14, 2, 17, 35, 9, 12, 7, 9, 40)
l: List[Int] = List(1, 14, 2, 17, 35, 9, 12, 7, 9, 40)
scala> def someMethod(l: List[Int], from: Int, to: Int) : List[Int] = {
| // some code here
| }
someMethod: (l: List[Int], from: Int, to: Int)List[Int]
scala> someMethod(l, 2, 7)
res0: List[Int] = List(2, 17, 35, 9, 12, 7)
Expected output:
For lists that don't contain 2 and/or 7: an empty list
Input: (1, 2, 2, 2, 3, 4, 7, 8); Output: (2, 2, 2, 3, 4, 7)
Input: (1, 2, 3, 4, 7, 7, 7, 8); Output: (2, 3, 4, 7)
Input: (1, 2, 3, 4, 7, 1, 2, 3, 5, 7, 8); Output: ((2, 3, 4, 7), (2, 3, 5, 7))
Too bad that the regex-engines work only with strings, not with general lists - would be really nice if you could find all matches for something like L.*?R with two arbitrary delimiters L and R. Since it doesn't work with regex, you have to build a little automaton yourself. Here is one way to do it:
#annotation.tailrec
def findDelimitedSlices[A](
xs: List[A],
l: A,
r: A,
revAcc: List[List[A]] = Nil
): List[List[A]] = {
xs match {
case h :: t => if (h == l) {
val idx = xs.indexOf(r)
if (idx >= 0) {
val (s, rest) = xs.splitAt(idx + 1)
findDelimitedSlices(rest, l, r, s :: revAcc)
} else {
revAcc.reverse
}
} else {
findDelimitedSlices(t, l, r, revAcc)
}
case Nil => revAcc.reverse
}
}
Input:
for (example <- List(
List(1, 2, 2, 2, 3, 4, 7, 8),
List(1, 2, 3, 4, 7, 7, 7, 8),
List(1, 2, 3, 4, 7, 1, 2, 3, 5, 7, 8)
)) {
println(findDelimitedSlices(example, 2, 7))
}
Output:
List(List(2, 2, 2, 3, 4, 7))
List(List(2, 3, 4, 7))
List(List(2, 3, 4, 7), List(2, 3, 5, 7))
You're looking for slice:
# l.slice(2, 7)
res1: List[Int] = List(2, 17, 35, 9, 12)
# l.slice(2, 8)
res2: List[Int] = List(2, 17, 35, 9, 12, 7)

How to summarize lists in Scala?

to All!
i have this data structure:
List[List[String]]
all List[String] are the same size, it looks like:
List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
i need to summarize columns in this lists like this:
val result = List(1 + 4 + 7, 2 + 5 + 8, 3 + 6 + 9)
with such algorithm
res[0] = list1[0] + list2[0] + list3[0]
res[1] = list1[1] + list2[2] + list3[3]
...
help, please!
You're looking for the transpose method:
scala> val in = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
in: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9))
scala> in.transpose
res0: List[List[Int]] = List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9))
scala> in.transpose.map(_.sum)
res1: List[Int] = List(12, 15, 18)

How to split a collection into groups using the calculation of member as a predicate

I have a method that collect the consecutive number with the difference of no more than some number (2 in my example). This code is working just fine but it does zipping every time it is called, so I wonder if there is any better solution to this thanks.
def myGrouper(sortedData: Seq[Int], maxDif: Int): Seq[Seq[Int]] = sortedData match {
case Nil => Nil
case _ =>
val (grouped, rest) = sortedData.zipWithIndex.span{
case (num, idx) =>
if (idx > 1) Math.abs(sortedData(idx-1) - num) <= maxDif
else true
}
Seq(grouped.map(_._1)) ++ myGrouper(rest.map(_._1), maxDif)
}
val myList = Seq(1, 2, 3, 7, 8, 10, 15, 17, 19)
val maxDif = 2
println(myGrouper(myList, maxDif))
Below is the result from running this code
myList: Seq[Int] = List(1, 2, 3, 7, 8, 10, 15, 17, 19)
maxDif: Int = 2
List(List(1, 2, 3), List(7, 8, 10), List(15, 17, 19))
res0: Unit = ()

How can i interleave elements of 2 lists in scala

I'd like to combine two Lists of arbitrary length in such a way that elements from the 2nd List are inserted after every n-th element into the 1st List. If the 1st List length is less than n, no insertion results.
So having
val a = List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
val b = List(101,102,103)
val n = 3
I want the resulting List to look like this:
List(1,2,3,101,4,5,6,102,7,8,9,103,10,11,12,13,14,15)
I have this working using a foldLeft on a, but I'm wondering how the same logic could be accomplished using Scalaz?
Thanks for everyone's answers. They were all helpful to me !
Meet my apomorphism friend
def apo[A, B](v: B)(f: B => Option[(A, Either[B, List[A]])]): List[A] = f(v) match {
case None => Nil
case Some((a, Left(b))) => a :: apo(b)(f)
case Some((a, Right(as))) => a :: as
}
Your interleave method can be implemented like this
def interleave[A](period: Int, substitutes: List[A], elems: List[A]): List[A] =
apo((period, substitutes, elems)){
case (_, _, Nil) => None
case (_, Nil, v :: vs) => Some((v, Right(vs)))
case (0, x :: xs, vs) => Some((x, Left((period, xs, vs))))
case (n, xs, v :: vs) => Some((v, Left((n - 1, xs, vs))))
}
This gives:
scala> interleave(3, b, a)
res1: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103 , 10, 11 , 12, 13, 14, 15)
The good point is the computation ends when a or b are Nil unlike foldLeft. The bad news is interleave is no more tail recursive
This gets very simple with zipAll. Moreover, you are able to choose the amount of elements of the second array (in this case 1):
val middle = b.grouped(1).toList
val res = a.grouped(n).toList.zipAll(middle, Nil, Nil)
res.filterNot(_._1.isEmpty).flatMap(x => x._1 ++ x._2)
Or if you prefer, one-liner:
a.grouped(n).toList.zipAll(b.map(List(_)), Nil, Nil).filterNot(_._1.isEmpty).flatMap(x => x._1 ++ x._2)
You can also make an implicit class, so you could call a.interleave(b, 3) or with an optional thrid parameter a.interleave(b, 3, 1).
How about this:
def process[A](xs: List[A], ys: List[A], n: Int): List[A] =
if(xs.size <= n || ys.size == 0) xs
else xs.take(n):::ys.head::process(xs.drop(n),ys.tail,n)
scala> process(a,b,n)
res8: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
scala> val a = List(1,2,3,4,5,6,7,8,9,10,11)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
scala> process(a,b,n)
res9: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11)
scala> val a = List(1,2,3,4,5,6,7,8,9)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> process(a,b,n)
res10: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9)
scala> val a = List(1,2,3,4,5,6,7,8)
a: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8)
scala> process(a,b,n)
res11: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8)
Your request is "If the 1st List length is less than n, no insertion results", then my code should change to:
def process[A](xs: List[A], ys: List[A], n: Int): List[A] =
if(xs.size < n || ys.size == 0) xs
else xs.take(n):::ys.head::process(xs.drop(n),ys.tail,n)
What about:
def interleave[A](xs: Seq[A], ys: Seq[A], n: Int): Seq[A] = {
val iter = xs grouped n
val coll = iter zip ys.iterator flatMap { case (xs, y) => if (xs.size == n) xs :+ y else xs }
(coll ++ iter.flatten).toIndexedSeq
}
scala> interleave(a, b, n)
res34: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
scala> interleave(1 to 2, b, n)
res35: Seq[Int] = Vector(1, 2)
scala> interleave(1 to 6, b, n)
res36: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102)
scala> interleave(1 to 7 b, n)
res37: Seq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7)
scala> interleave(1 to 7, Nil, n)
res38: Seq[Int] = Vector(1, 2, 3, 4, 5, 6, 7)
scala> interleave(1 to 7, Nil, -3)
java.lang.IllegalArgumentException: requirement failed: size=-3 and step=-3, but both must be positive
It is short, but it is not the most efficient solution. If you call it with Lists for example, the append-operations (:+ and ++) are expensive (O(n)).
EDIT: I'm sorry. I notice now, that you want to have a solution with Scalaz. Nevertheless the answer may be useful therefore I won't delete it.
Without Scalaz and recursion.
scala> a.grouped(n).zip(b.iterator.map{ Some(_) } ++ Iterator.continually(None)).flatMap{ case (as, e) => if (as.size == n) as ++ e else as }.toList
res17: List[Int] = List(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
Generic way:
def filled[T, A, That](a: A, b: Seq[T], n: Int)(implicit bf: CanBuildFrom[A, T, That], a2seq: A => Seq[T]): That = {
val builder = bf()
builder.sizeHint(a, a.length / n)
builder ++= a.grouped(n).zip(b.iterator.map{ Some(_) } ++ Iterator.continually(None)).flatMap{ case (as, e) => if(as.size == n ) as ++ e else as }
builder.result()
}
Usage:
scala> filled("abcdefghijklmnopqrstuvwxyz", "1234", 3)
res0: String = abc1def2ghi3jkl4mnopqrstuvwxyz
scala> filled(1 to 15, 101 to 103, 3)
res1: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 101, 4, 5, 6, 102, 7, 8, 9, 103, 10, 11, 12, 13, 14, 15)
scala> filled(1 to 3, 101 to 103, 3)
res70: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 101)
scala> filled(1 to 2, 101 to 103, 3)
res71: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2)
here's the one you want:
import scala.annotation.tailrec
#tailrec
final def interleave[A](base: Vector[A], a: List[A], b: List[A]): Vector[A] = a match {
case elt :: aTail => interleave(base :+ elt, b, aTail)
case _ => base ++ b
}
...
interleave(Vector.empty, a, b)