Scala: List Operations - list

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

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)

how to find the max value in an IntList?

I'm writing a function which will find the largest element in an IntList. I know how to do this in Java, but can't understand how to do this at Scala.
I made it, Here is what I have so far, I think this should be it.
abstract class IntList
case class Nil() extends IntList
case class Cons(h: Int, t: IntList) extends IntList
object ListFuns {
// return the maximum number in is
// return the maximum number in is
def maximum(is: IntList): Int = is match {
case Nil() => 0
case list => max(head(is), tail(is))
}
def head(l : IntList) : Int = l match {
case Nil() => 0
case Cons(e,tail) => e
}
def tail(l : IntList) : IntList = l match {
case Nil() => Nil()
case Cons(e,tail) => tail
}
def max(n : Int, l : IntList) : Int = l match {
case Nil() => n
case l => {
val h = head(l)
var champ = 0
if(n > h) {
champ = n
n
}
else{
champ = h
h
}
if(tail(l) == Nil()){
champ
}
else{
max(champ, tail(l))
}
}
}
}
Pattern matching would make it much shorter :
def maximum(l: IntList) : Int = l match {
case Cons(singleValue, Nil) => singleValue
case Nil() => // you decide, 0, the min value of ints, throw....
case Cons(head, tail) =>
val maxOfTail = maximum(tail)
if(maxOfTail > head) maxOfTail else head
}
minor notes:
you can change case class Nil() to case object Nil
the last two lines should be just head max maximum(tail), or head.max(maximum(tail)), whichever you are more comfortable with (they are the same thing).
This is just a starting point, as you learn further, you will find that my method not being tail-recursive is not too good. You might also consider whether you could return an Option to account for the empty list case. Also, notice that implementation of maximum, minimum, sum, product... are very similar, and try to factor that out.

Removing value from range

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

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: how to split using more than one delimiter

I would like to know how I can split a string using more than one delimiter with Scala.
For instance if I have a list of delimiters :
List("Car", "Red", "Boo", "Foo")
And a string to harvest :
Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed
I would like to be able to output something like :
List( ("Car", " foerjfpoekrfopekf "),
("Red", " ezokdpzkdpoedkzopke dekpzodk "),
("Foo", " azdkpodkzed")
)
You can use the list to create a regular expression and use its split method:
val regex = List("Car", "Red", "Boo", "Foo").mkString("|").r
regex.split("Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed")
That however doesn't tell you which delimiter was used where. If you need that, I suggest you try Scala's parser library.
EDIT:
Or you can use regular expressions to extract one pair at a time like this:
def split(s:String, l:List[String]):List[(String,String)] = {
val delimRegex = l.mkString("|")
val r = "("+delimRegex+")(.*?)(("+delimRegex+").*)?"
val R = r.r
s match {
case R(delim, text, rest, _) => (delim, text) :: split(rest, l)
case _ => Nil
}
}
a bit verbose, but it works:
DEPRECATED VERSION: (it has a bug, left it here because you already accepted the answer)
def f(s: String, l: List[String], g: (String, List[String]) => Int) = {
for {
t <- l
if (s.contains(t))
w = s.drop(s.indexOf(t) + t.length)
} yield (t, w.dropRight(w.length - g(w, l)))
}
def h(s: String, x: String) = if (s.contains(x)) s.indexOf(x) else s.length
def g(s: String, l: List[String]): Int = l match {
case Nil => s.length
case x :: xs => math.min(h(s, x), g(s, xs))
}
val l = List("Car", "Red", "Boo", "Foo")
val s = "Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed"
output:
f(s, l, g).foreach(println)
> (Car, foerjfpoekrfopekf )
> (Red, ezokdpzkdpoedkzopke dekpzodk )
> (Foo, azdkpodkzed)
it returns Array[String] instead of list. but you can just as well do: f(s, l, g).toList
EDIT:
just noticed this code is good if the delimiters only appear once in the string. if had defined s as follows:
val s = "Car foerjfpoekrfopekf Red ezokdpzkdpoedkzopke dekpzodk Foo azdkpodkzed Car more..."
I'd still get the same result, instead of another pair ("Car"," more...")
EDIT#2: BUGLESS VERSION here's the fixed snippet:
def h(s: String, x: String) = if (s.contains(x)) s.indexOf(x) else s.length
def multiSplit(str: String, delimiters: List[String]): List[(String, String)] = {
val del = nextDelimiter(str, delimiters)
del._1 match {
case None => Nil
case Some(x) => {
val tmp = str.drop(x.length)
val current = tmp.dropRight(tmp.length - nextDelIndex(tmp,delimiters))
(x, current) :: multiSplit(str.drop(x.length + current.length), delimiters)
}
}
}
def nextDelIndex(s: String, l: List[String]): Int = l match {
case Nil => s.length
case x :: xs => math.min(h(s, x), nextDelIndex(s, xs))
}
def nextDelimiter(str: String, delimiters: List[String]): (Option[String], Int) = delimiters match {
case Nil => (None, -1)
case x :: xs => {
val next = nextDelimiter(str, xs)
if (str.contains(x)) {
val i = str.indexOf(x)
next._1 match {
case None => (Some(x), i)
case _ => if (next._2 < i) next else (Some(x), i)
}
} else next
}
}
output:
multiSplit(s, l).foreach(println)
> (Car, foerjfpoekrfopekf )
> (Red, ezokdpzkdpoedkzopke dekpzodk )
> (Foo, azdkpodkzed)
> (Car, more...)
and now it works :)