Removing value from range - list

I have the following case class:
case class objRanges(rangeVals:List[rangeNums])
where rangeNums represents a range of values and is also a case class:
case class rangeNums(lowValue:Int, highValue:Int)
I would like to implement a subtraction method for objRanges, one with the following signature:
def -(numberRemove:Int): objRanges = {
The number would then be removed from all the ranges in the list rangeVals, splitting rangeNums that contain the number into two rangeNums (one from lowValue to n-1 and another from n+1 to highValue). Would this be easier to implement using a for comprehension or foldLeft?
For example, rangeVals currently holds the elements:
[(1,3),(5,10)]
Calling the - method with 7 as a parameter should return a new instance of objRanges with the elements:
[(1,3),(5,6),(8,10)]
While subtracting an element which is the lower bound of a range should just increase the lower bound by one, so subtracting 5 in the rangeVals should return:
[(1,3),(6,10)]
The same applies for the upper bound. If rangeVals currently holds:
[(1,3),(5,7)]
Then removing 7 should return
[(1,3),(5,6)]
The last boundary case would be where there is only one number in a range, and that number is to be deleted. For example, if RangeVals currently holds:
[(1,3),(7,7)]
Removing 7 should just remove the entire range, returning a new instance with rangeVals equal to:
[(1,3)]
And how would the solution change if I was looking instead to remove all numbers in the ranges less than numberRemove?

Using map:
case class RangeNums(lowValue: Int, highValue: Int)
case class ObjRanges(rangeVals: List[RangeNums]) {
def -(n: Int): ObjRanges = {
val res = rangeVals.map {
case e # RangeNums(l, h) =>
if (n > l && n < h) RangeNums(l, n - 1) :: RangeNums(n + 1, h) :: Nil
else if (n == l) RangeNums(l + 1, h) :: Nil
else if (n == h) Nil
else e :: Nil
}.flatten
ObjRanges(res)
}
}
test with REPL:
scala> val l = RangeNums(0, 10) :: RangeNums(1, 3) :: Nil
l: List[RangeNums] = List(RangeNums(0,10), RangeNums(1,3))
scala> val r = ObjRanges(l)
r: ObjRanges = ObjRanges(List(RangeNums(0,10), RangeNums(1,3)))
scala> r - 5
res0: ObjRanges = ObjRanges(List(RangeNums(0,4), RangeNums(6,10), RangeNums(1,3)))
scala> r - 2
res1: ObjRanges = ObjRanges(List(RangeNums(0,1), RangeNums(3,10), RangeNums(1,1), RangeNums(3,3)))
scala> r - 10
res2: ObjRanges = ObjRanges(List(RangeNums(1,3)))
scala> r - 0
res3: ObjRanges = ObjRanges(List(RangeNums(1,10), RangeNums(1,3)))
A tailrec solution:
import scala.annotation.tailrec
case class ObjRanges(rangeVals: List[RangeNums]) {
def -(n: Int): ObjRanges = {
#tailrec
def minRec(n: Int, rem: List[RangeNums], accu: List[RangeNums]): List[RangeNums] =
rem match {
case (e # RangeNums(l, h)) :: t =>
val tmpRes =
if (n > l && n < h) RangeNums(n + 1, h) :: RangeNums(l, n - 1) :: accu
else if (n == l) RangeNums(l + 1, h) :: accu
else if (n == h) accu
else e :: accu
minRec(n, t, tmpRes)
case Nil =>
accu
}
ObjRanges(minRec(n, rangeVals, Nil).reverse)
}
}
Using fold:
case class ObjRanges(rangeVals: List[RangeNums]) {
def -(n: Int): ObjRanges = {
def minF(accu: List[RangeNums], e: RangeNums) = {
val l = e.lowValue
val h = e.highValue
if (n > l && n < h) RangeNums(n + 1, h) :: RangeNums(l, n - 1) :: accu
else if (n == l) RangeNums(l + 1, h) :: accu
else if (n == h) accu
else e :: accu
}
val res = (List[RangeNums]() /: rangeVals)((accu, e) => minF(accu, e))
ObjRanges(res.reverse)
}
}

Related

Scala: slice a list from the first non-zero element

Suppose I have a list filled with zeroes
val a = List(0,0,0,0,2,4,0,6,0,7)
I want to slice away the zeroes preceding the first non-zero element and also return the index where the 1st non-zero element is present.
Foe the above case I want an output:
output = List(2,4,0,6,0,7)
idx = 4
How do I do it?
First, you can use zipWithIndex to conveniently pair each element with its index. Then use dropWhile to return all of the preceding zero elements. From there, you'll have all of the remaining elements paired with their indices from the original List. You can unzip them. Since this may result in an empty list, the index you're looking for should be optional.
scala> val (remaining, indices) = a.zipWithIndex.dropWhile { case (a, i) => a == 0 }.unzip
remaining: List[Int] = List(2, 4, 0, 6, 0, 7) // <--- The list you want
indices: List[Int] = List(4, 5, 6, 7, 8, 9)
scala> val index = indices.headOption
index: Option[Int] = Some(4) // <--- the index of the first non-zero element
This is a use-case for span:
val a = List(0,0,0,0,2,4,0,6,0,7)
val (zeros, output) = a.span(_ == 0)
val idx = zeros.length
use dropWhile:
val output = a.dropWhile{ _ == 0 }
val idx = output.headOption
.map(_ => a.length - output.length)
.getOrElse(-1) // index starting from 0, -1 if not found
Sightly modified from #bottaio answer, but returning an Option[Int] instead of a plain Int for the index.
def firstNonZero(l: List[Int]): (Option[Int], List[Int]) = {
#annotation.tailrec
def go(remaining: List[Int], idx: Int): (Int, List[Int]) =
remaining match {
case Nil => idx -> Nil
case 0 :: xs => go(remaining = xs, idx + 1)
case xs => idx -> xs
}
l match {
case 0 :: xs =>
val (idx, list) = go(remaining = xs, idx = 1)
Some(idx) -> list
case list =>
None -> list
}
}
Just another solution using foldLeft:
val (i, l) =
a.foldLeft((None: Option[Int], List.empty: List[Int]))((b, n) => {
if (n == 0 && b._2.isEmpty) (b._1.orElse(Some(0)).map(_ + 1), List.empty)
else (b._1.orElse(Some(0)), b._2 :+ n)
})
i: Option[Int] = Some(4)
l: List[Int] = List(2, 4, 0, 6, 0, 7)
You can do it pretty clean with indexWhere:
val idx = a.indexWhere(_!=0)
val output = a.drop(idx)
Others have provided answers that requires multiple list traversals. You can write a recursive function to calculate that in a single pass:
def firstNonZero(l: List[Int]): (Int, List[Int]) = {
#tailrec
def go(l: List[Int], idx: Int): (Int, List[Int]) = l match {
case Nil => (idx, Nil)
case 0 :: xs => go(xs, idx + 1)
case xs => (idx, xs)
}
go(l, 0)
}
what is also equivalent to
val (leadingZeros, rest) = a.span(_ == 0)
val (index, output) = (leadingZeros.length, rest)

Scala: List Operations

In Scala, define the function slice(from, until, xs) that selects an interval of elements from the (string) list xs such that for each element x in the interval the following invariant holds: from <= indexOf(x) < until.
from: the lowest index to include from this list.
until: the highest index to exclude from this list.
returns: a list containing the elements greater than or equal to index from extending up to (but not including) index until of this list.
example:
def test {
expect (Cons("b", Cons("c", Nil()))) {
slice(1, 3, Cons("a", Cons("b", Cons("c", Cons("d", Cons("e", Nil()))))))
}
}
another example:
def test {
expect (Cons("d", Cons("e", Nil()))) {
slice(3, 7, Cons("a", Cons("b", Cons("c", Cons("d", Cons("e", Nil()))))))
}
}
and this is what I have, but its not that correct. Can someone help me with it?
abstract class StringList
case class Nil() extends StringList
case class Cons(h: String, t: StringList) extends StringList
object Solution {
// define function slice
def slice(from : Int, until : Int, xs : StringList) : StringList = (from, until, xs) match {
case (_,_,Nil()) => Nil()
case (n, m, _) if(n == m) => Nil()
case (n, m, _) if(n > m) => Nil()
case (n, m, _) if(n < 0) => Nil()
case (n, m, xs) if(n == 0)=> Cons(head(xs), slice(n+1,m,tail(xs)))
case (n, m, xs) => {
//Cons(head(xs), slice(n+1,m,tail(xs)))
if(n == from) {
print("\n")
print("n == m " + Cons(head(xs), slice(n+1,m,tail(xs))))
print("\n")
Cons(head(xs), slice(n+1,m,tail(xs)))
}
else slice(n+1,m,tail(xs))
}
}
def head(t : StringList) : String = t match {
case Nil() => throw new NoSuchElementException
case Cons(h, t) => h
}
def tail(t : StringList) : StringList = t match {
case Nil() => Nil()
case Cons(h, t) => t
}
/* def drop(n : Int, t : StringList) : StringList = (n, t) match {
case (0, t) => t
case (_, Nil()) => Nil()
case (n, t) => drop(n-1 , tail(t))
}*/
}//
This works add a method to find the element at given index :
trait StringList
case class Nil() extends StringList
case class Cons(h: String, t: StringList) extends StringList
object Solution {
def numberOfElements(str: StringList, count: Int = 0): Int = {
if (str == Nil()) count else numberOfElements(tail(str), count + 1)
}
def elemAtIndex(n: Int, str: StringList, count: Int = 0): String = {
if (str == Nil() || n == count) head(str) else elemAtIndex(n, tail(str), count + 1)
}
def head(str: StringList): String = str match {
case Nil() => throw new NoSuchElementException
case Cons(h, t) => h
}
def tail(str: StringList): StringList = str match {
case Nil() => Nil()
case Cons(h, t) => t
}
// define function slice
def slice(from: Int, until: Int, xs: StringList): StringList = (from, until, xs) match {
case (n, m: Int, _) if n == m || n > m || n < 0 => Nil()
case (n, m: Int, xs: StringList) =>
if (m > numberOfElements(xs)) {
slice(n, numberOfElements(xs), xs)
} else {
Cons(elemAtIndex(n, xs), slice(n + 1, m, xs))
}
}
}
scala> Solution.slice(1, 3, Cons("a", Cons("b", Cons("c", Cons("d", Cons("e", Nil()))))))
res0: StringList = Cons(b,Cons(c,Nil()))
scala> Solution.slice(3, 7, Cons("a", Cons("b", Cons("c", Cons("d", Cons("e", Nil()))))))
res0: StringList = Cons(d,Cons(e,Nil()))

Method that add and remove an element from a List

i'm writing a method that take a list: List[(String, Int)] , x:(String, Int) and a n: Int parameters and return a List[(String, Int)]
The list parameter represents the input list, the x element represents the element to add to the list, the n represents the maximum dimension of the list.
The method has the following behavior:
First of all check if the list has n elements.
If list has
less than n elements, the method add the x elements to the list.
Otherwise if the list contain an elements less than x, the
method remove the minimum element from the list, and add the x
element to the list.
I've implemented the method as the following:
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if(list.size < n)
list :+ x
else {
var index = -1
var min = 10000000//some big number
for(el <- 0 to list.size) {
if(list(el)._2 < x._2 && list(el)._2 < min) {
min = list(el)._2
index = el
}
}
if(index != -1) {
val newList = list.drop(index)
newList :+ x
}
else list
}
}
Exist a way to express this behavior in a more clean way??
First, a corrected version of what you posted (but it appears, not what you intended)
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if(list.size < n)
list :+ x
else {
var index = -1
for(i <- 0 until list.size) {
val el = list(i)
if(el._2 < x._2)
index = i
}
if(index != -1) {
val (before, after) = list.splitAt(index)
val newList = before ++ after.tail
newList :+ x
}
else list
}
}
And some tests
val l1 = List(("one", 1))
val l2 = method(l1, ("three", 3), 2)
//> l2 : List[(String, Int)] = List((one,1), (three,3))
val l3 = method(l2, ("four", 4), 2)
//> l3 : List[(String, Int)] = List((one,1), (four,4))
val l4 = method(l2, ("zero", 0), 2)
//> l4 : List[(String, Int)] = List((one,1), (three,3))
Neater version (but still not meeting the spec as mentioned in a comment from the OP)
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if (list.size < n)
list :+ x
else {
val (before, after) = list.span(_._2 >= x._2)
if (after.isEmpty)
list
else
before ++ after.tail :+ x
}
}
Another version that always removes the minimum, if that's less than x.
def method(list: List[(String, Int)], x: (String, Int), n: Int) = {
if (list.size < n)
list :+ x
else {
val smallest = list.minBy(_._2)
if (smallest._2 < x._2) {
val (before, after) = list.span(_ != smallest)
before ++ after.tail :+ x
} else
list
}
}
and its test results
val l1 = List(("one", 1))
val l2 = method(l1, ("three", 3), 2)
//> l2 : List[(String, Int)] = List((one,1), (three,3))
val l3 = method(l2, ("four", 4), 2)
//> l3 : List[(String, Int)] = List((three,3), (four,4))
val l4 = method(l2, ("zero", 0), 2)
//> l4 : List[(String, Int)] = List((one,1), (three,3))
but as I say in a comment, better to use a method that processes the whole sequence of Xs and returns the top N.
I would separate the ordering from the method itself:
def method[A: Ordering](list: List[A], x: A, n: Int) = ...
What do you want to do if the list contains more than one element less than x? If you're happy with replacing all of them, you could use map rather than your handwritten loop:
list map {
case a if Ordering.lt(a, x) => x
case a => a
}
If you only want to replace the smallest element of the list, maybe it's neater to use min?
val m = list.min
if(m < x) {
val (init, m :: tail) = list.splitAt(list.indexOf(m))
init ::: x :: tail
else list

How to split a List to tuples?

I am trying to define a function, that would take a list and split it down n without using take, drop or grouped
def mySplit[X](n: Int, xs: List[X]): (List[X], List[X]) = {
if (n <= 0) (Nil, xs)
else
if (n >= xs.size) (xs, Nil)
else
if (n < xs.tail.size) (xs.head :: mySplit(n, xs.tail), Nil)
else (Nil, xs.head :: mySplit(n, xs.tail))
}
Here is what I am thinking. If n < xs.tail.size we can build up tuple 1 (representing part 1), else we can work on tuple 2 (second part of the list).
The above does not work. It seems that it does not like the :: when I am constructing part of a tuple.
Am I approaching this the right way?
Example: mySplit(3, (1 to 5).toList) should return (List(1,2,3), List(4,5))
Here is my take, rewritten from scratch:
def mySplit[X](n: Int, xs: List[X]): (List[X], List[X]) = {
xs match {
case Nil => (Nil, Nil)
case head :: tail =>
if(n == 0)
(Nil, xs)
else
mySplit(n - 1, tail) match {
case (before, after) =>
(head :: before, after)
}
}
}
Or alternatively and shorter:
def mySplit[X](n: Int, xs: List[X]): (List[X], List[X]) = {
n match {
case 0 => (Nil, xs)
case s =>
mySplit(s - 1, xs.tail) match {
case (before, after) =>
(xs.head :: before, after)
}
}
}
If you still want to split large lists, here is a tail recursive variant. Its also faster:
import scala.annotation.tailrec
def mySplit[X](n: Int, xs: List[X]): (List[X], List[X]) = {
require(n >= 0)
if (n > 0) {
var result: (List[X], List[X]) = null
#tailrec
def mySplit0(n: Int, l: List[X], r: List[X]): Unit = r match {
case h :: t if (n > 0) => mySplit0(n - 1, h :: l, t)
case _ => result = (l.reverse, r)
}
mySplit0(n, Nil, xs)
result
} else (Nil, xs)
}

Scala best way to make uniform crossover operation with permutation list?

I search the best and the most elegant way to make GA crossover operator in Scala functional (No "for" loop, with only immutable type if possible), for example, with this list:
val A = IndexedSeq (5,4,8)
val B = IndexedSeq (3,2,6)
I want to make random bitcoin permutation (with rng.nextBoolean for example) between each element in my IndexedSeq, and finally I get the two lists A' and B' after permutation of their elements.
Example of execution:
rng.nextBoolean <- (true,false,true)
A' = 3,4,6
B' = 5,2,8
Thanks.
def crossover[T](a: Seq[T], b: Seq[T], rs: Seq[Boolean]) =
(a, b, rs).zipped.map((x, y, z) => if (z) Seq(x, y) else Seq(y, x)).transpose
Use with Booleans as third argument:
scala> val Seq(a1, b1) = crossover(A, B, List(true, false, true))
a1: Seq[Int] = Vector(5, 2, 8)
b1: Seq[Int] = Vector(3, 4, 6)
If you want it with a default sequence of Booleans, you could provide a default argument like this:
def crossover[T](a: Seq[T], b: Seq[T], rs: Seq[Boolean] = {
val rng = new util.Random
Stream.continually(rng.nextBoolean) }) =
(a, b, rs).zipped.map((x, y, z) => if (z) Seq(x, y) else Seq(y, x)).transpose
Wow, where's all this code coming from? Here:
val (a1, b1) = A zip B map (t => if (util.Random.nextBoolean) t.swap else t) unzip
There, that's all.
If you already have a list of random booleans, you can do this:
val (a1, b1) = A zip B zip C map { case (t, flag) => if (flag) t.swap else t } unzip
import scala.util.Random
val A = IndexedSeq(5,4,8)
val B = IndexedSeq(3,2,6)
def crossover[T](rng: Random)(a: Seq[T], b: Seq[T]): (Seq[T],Seq[T]) = {
if (a.isEmpty && b.isEmpty) return (Nil,Nil)
val (aTailCrossover,bTailCrossover) = crossover(rng)(a.tail,b.tail)
if (rng.nextBoolean) (b.head +: aTailCrossover, a.head +: bTailCrossover)
else (a.head +: aTailCrossover, b.head +: bTailCrossover)
}
println(crossover(new Random)(A,B))
def rndCombi [T] (a: Seq[T], b: Seq[T]): Seq[T] = {
if (a.size != b.size) sys.error ("sizes don't match: a:" + a.size + " != b: " + b.size)
val rnd = util.Random
val max = (math.pow (2, a.size)).toInt
val r = rnd.nextInt (max)
def pick (a: Seq[T], b: Seq[T], r: Int) : List[T] = {
if (a.size == 0) Nil else
if (r % 2 == 0) a.head :: pick (a.tail , b.tail, r/2) else
b.head :: pick (a.tail , b.tail, r/2)
}
// print all combinations for testing:
// (0 until max).map (i => println (pick (a, b, i).mkString ("-")))
pick (a, b, r).toSeq
}
// I choosed different values for easy testing:
val a = IndexedSeq (7, 8, 9)
val b = IndexedSeq (1, 2, 3)
println (rndCombi (a, b).mkString (" "))
println (rndCombi (a, b.tail).mkString (" "))
Initializing util.Random each time is of course not very clever, if done frequently. So for production code you would rearrange the code.
If you don't restrict the input to 2 sequences, it get's more interesting. Here we go:
def rndCombi [T] (s: Seq[Seq[T]]): Seq[T] = {
val outer = s.size
val inner = s(0).size
val rnd = util.Random
val max = (math.pow (outer, inner)).toInt
val r = rnd.nextInt (max)
def pick (s: Seq[Seq[T]], r: Int, pos: Int = 0) : List[T] =
if (pos == inner) Nil
else s(r % inner)(pos) :: pick (s, r/inner, pos + 1)
// print all combinations for testing:
(0 until max).map (i => println (pick (s, i).mkString ("-")))
println ()
pick (s, r).toSeq
}
val a = IndexedSeq (1, 2, 3)
val b = IndexedSeq (4, 5, 6)
val c = IndexedSeq (7, 8, 9)
println (rndCombi (Seq (a, b, c)).mkString (" "))
The second solution can, of course, be used for 2 sequences as well.