Remove specific element on list with math logic in scala - scala

If I have this list:
val aList = List(1,1,1,3,4),List(3,3,5,6,7),List(7,7,7,6,7),List(2,3,3,2,6)
How do I update the list by eliminating non-duplicated numbers on the first head of the List? so the result should be:
val aRes = List(1,1,1), List(3,3), List(7,7,7)
List(2,3,3,2,6) should be removed also since we don't have 3 at the head of the list. My expectation for the result was:
val aRes = aList(1) map {case List(i) => List(aList.groupBy(_(1))}
But it seems not valid for this logic.
beside that, I also need to translate those result values to another list member:
val aScore = List(
/*score for 1*/ List(0, 0, 1500, 2500, 5000),
/*score for 2*/ List(0, 0, 500, 1000, 2000),
/*score for 3*/ List(0, 50, 100, 200, 500),
/*score for 4*/ List(0, 10, 50, 100, 150),
/*score for 5*/ List(0, 10, 50, 100, 150),
/*score for 6*/ List(0, 10, 50, 100, 150),
/*score for 7*/ List(0, 10, 50, 100, 150)
)
val score = ???
so from above aList result, the score must be 1500+50+50 = 1600 as result from 1*3=>1500, 3*2=>50 and 7*3=>50

You want to return something if there are duplicates, and nothing if not, so make a function that returns an Option:
def f(xs: List[Int]) = xs match {
case x0 :: x1 :: _ if x0 == x1 => Some(xs.takeWhile(_ == x0))
case _ => None
}
Then flatMap your list to that to get rid of the optiony bits:
aList.flatMap(f)
For the second part:
def getScore(xs: List[Int]) = aScore(xs.head - 1)(xs.size - 1)
So just map and sum the elements. In total:
aList.flatMap(f).map(getScore).sum
// result = 1600

object parseData {
val inputList = List(List(1,1,1,3,4),List(3,3,5,6,7),List(7,7,7,6,7),List(2,3,3,2,6))
val aScore = List(
/*score for 1*/ List(0, 0, 1500, 2500, 5000),
/*score for 2*/ List(0, 0, 500, 1000, 2000),
/*score for 3*/ List(0, 50, 100, 200, 500),
/*score for 4*/ List(0, 10, 50, 100, 150),
/*score for 5*/ List(0, 10, 50, 100, 150),
/*score for 6*/ List(0, 10, 50, 100, 150),
/*score for 7*/ List(0, 10, 50, 100, 150)
)
def isDuplicated(aList: List[Int]): Boolean = aList.head == aList.tail.head
def getRidOfNonDuplicates(aList: List[Int]): List[Int] = {
val opList = ListBuffer(aList.head)
def loop(aList: List[Int], opList: ListBuffer[Int]): Unit = {
if (aList.tail == Nil) return
if (aList.head == aList.tail.head) opList += aList.tail.head
loop(aList.tail, opList)
}
loop(aList, opList)
opList.toList
}
def printaScoreValue(aList: List[Int]): Unit = println(aScore(aList.head - 1)(aList.length - 1))
val outputList = inputList.filter(isDuplicated(_))
val opList = ListBuffer.empty[List[Int]]
for (aList <- outputList)
opList += getRidOfNonDuplicates(aList)
opList.foreach(printaScoreValue(_))
}
gives
1500
50
50

My first stab was:
scala> val ls = List(List(1,1,1,3,4),List(3,3,5,6,7),List(7,7,7,6,7),List(2,3,3,2,6))
ls: List[List[Int]] = List(List(1, 1, 1, 3, 4), List(3, 3, 5, 6, 7), List(7, 7, 7, 6, 7), List(2, 3, 3, 2, 6))
scala> ls map {
_ groupBy identity filter { case (i, is) => is.length > 1 } flatMap { _._2 }
}
res2: List[List[Int]] = List(List(1, 1, 1), List(3, 3), List(7, 7, 7, 7), List(2, 2, 3, 3))
But as you can see, it not quite what you want. I think the next one nails it:
scala> ls map { l =>
val (h,t) = (l.head, l.tail)
h :: t.takeWhile( _ == h )
} filter { _.length > 1 }
res7: List[List[Int]] = List(List(1, 1, 1), List(3, 3), List(7, 7, 7))
But notice, it is not going to work if List.empty is an element of the outer list.

Related

Scala Split Seq or List by Delimiter

Let's say I have a sequence of ints like this:
val mySeq = Seq(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
I want to split this by let's say 0 as a delimiter to look like this:
val mySplitSeq = Seq(Seq(0, 1, 2, 1), Seq(0, -1), Seq(0, 1, 2, 3, 2))
What is the most elegant way to do this in Scala?
This works alright
mySeq.foldLeft(Vector.empty[Vector[Int]]) {
case (acc, i) if acc.isEmpty => Vector(Vector(i))
case (acc, 0) => acc :+ Vector(0)
case (acc, i) => acc.init :+ (acc.last :+ i)
}
where 0 (or whatever) is your delimiter.
Efficient O(n) solution
Tail-recursive solution that never appends anything to lists:
def splitBy[A](sep: A, seq: List[A]): List[List[A]] = {
#annotation.tailrec
def rec(xs: List[A], revAcc: List[List[A]]): List[List[A]] = xs match {
case Nil => revAcc.reverse
case h :: t =>
if (h == sep) {
val (pref, suff) = xs.tail.span(_ != sep)
rec(suff, (h :: pref) :: revAcc)
} else {
val (pref, suff) = xs.span(_ != sep)
rec(suff, pref :: revAcc)
}
}
rec(seq, Nil)
}
val mySeq = List(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
println(splitBy(0, mySeq))
produces:
List(List(0, 1, 2, 1), List(0, -1), List(0, 1, 2, 3, 2))
It also handles the case where the input does not start with the separator.
For fun: Another O(n) solution that works for small integers
This is more of warning rather than a solution. Trying to reuse String's split does not result in anything sane:
val mySeq = Seq(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
val z = mySeq.min
val res = (mySeq
.map(x => (x - z).toChar)
.mkString
.split((-z).toChar)
.map(s => 0 :: s.toList.map(_.toInt + z)
).toList.tail)
It will fail if the integers span a range larger than 65535, and it looks pretty insane. Nevertheless, I find it amusing that it works at all:
res: List[List[Int]] = List(List(0, 1, 2, 1), List(0, -1), List(0, 1, 2, 3, 2))
You can use foldLeft:
val delimiter = 0
val res = mySeq.foldLeft(Seq[Seq[Int]]()) {
case (acc, `delimiter`) => acc :+ Seq(delimiter)
case (acc, v) => acc.init :+ (acc.last :+ v)
}
NOTE: This assumes input necessarily starts with delimiter.
One more variant using indices and reverse slicing
scala> val s = Seq(0,1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).reverse.map( {var p=0; x=>{ val y=s.slice(x,s.size-p);p=s.size-x;y}}).reverse
res173: scala.collection.immutable.IndexedSeq[scala.collection.mutable.Seq[Int]] = Vector(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
if the starting doesn't have the delimiter, then also it works.. thanks to jrook
scala> val s = Seq(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).reverse.map( {var p=0; x=>{ val y=s.slice(x,s.size-p);p=s.size-x;y}}).reverse
res174: scala.collection.immutable.IndexedSeq[scala.collection.mutable.Seq[Int]] = Vector(ArrayBuffer(1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
UPDATE1:
More compact version by removing the "reverse" in above
scala> val s = Seq(0,1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).:+(s.size).sliding(2,1).map( x=>s.slice(x(0),x(1)) ).toList
res189: List[scala.collection.mutable.Seq[Int]] = List(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
scala> val s = Seq(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).:+(s.size).sliding(2,1).map( x=>s.slice(x(0),x(1)) ).toList
res190: List[scala.collection.mutable.Seq[Int]] = List(ArrayBuffer(1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
scala>
Here is a solution I believe is both short and should run in O(n):
def seqSplitter[T](s: ArrayBuffer[T], delimiter : T) =
(0 +: s.indices.filter(s(_)==delimiter) :+ s.size) //find split locations
.sliding(2)
.map(idx => s.slice(idx.head, idx.last)) //extract the slice
.dropWhile(_.isEmpty) //take care of the first element
.toList
The idea is to take all the indices where the delimiter occurs, slide over them and slice the sequence at those locations. dropWhile takes care of the first element being a delimiter or not.
Here I am putting all the data in an ArrayBuffer to ensure slicing will take O(size_of_slice).
val mySeq = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
seqSplitter(mySeq, 0).toList
Gives:
List(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
A more detailed complexity analysis
The operations are:
Filter the delimiter indices (O(n))
loop over a list of indices obtained from previous step (O(num_of_delimeters)); for each pair of indices corresponding to a slice:
Copy the slice from the array and put it into the final collection (O(size_of_slice))
The last two steps sum up to O(n).

Create and Append list based on other list member in Scala

I have list of Integer like this:
val aRowcol: List[List[Int]]] =
List(List(0, 0), List(0, 1), List(0, 2)),
List(List(1, 0), List(1, 1), List(1, 2)),
List(List(2, 0), List(2, 1), List(2, 2)),
List(List(0, 0), List(1, 1), List(2, 2)),
List(List(2, 0), List(1, 1), List(0, 2)),
List(List(1, 0), List(0, 1), List(0, 2)),
List(List(1, 0), List(2, 1), List(2, 2))
val aAlpha: List[List[String]] = List(
List("a","b","c","d"),
List("e","f","g","h"),
List("i","j","k","l","m"))
val i = 4
val resNum:List[List[Int,String]] = (0 to i) {
_map => List(
aRowcol.take(i).head.head,
aRowcol.take(i).head(1),
aAlpha(aRowcol.take(i).head.head)(aRowcol.take(i).head(1))}
.toList
But the result I want for val resNum is:
List(
List(0,0,"a"),
List(1,0,"e"),
List(2,0,"i"),
List(0,0,"a"),
List(2,0,"i"))
(0,0) means first row first column, we have "a" on that possition, so i will define how many aAlpha we will have. I think it will be much easier if we do i++, but you know that we couldn't do i++ in scala.
I'm guessing that you want to treat the first element in each "list of lists" in aRowcol as the "coordinates" of a letter in aAlpha, and want to append that letter to each of these "first elements".
If so:
val result: List[List[Any]] = aRowcol.take(5) // only 5 first rows
.map(_.head) // first List(i, j) only, the rest is ignored
.map { case List(i, j) => List(i, j, aAlpha(i)(j)) } // append the right letter to list
result.foreach(println)
// List(0, 0, a)
// List(1, 0, e)
// List(2, 0, i)
// List(0, 0, a)
// List(2, 0, i)
If that's not what you meant - please clarify.
EDIT: as for your version - it can work (and achieve the same goal) with a few fixes:
list.take(i) doesn't return the i-th element, it returns a list with the first i elements, I think you're trying to use list.apply(i) which returns the i-th element, or it's shorthand version: list(i)
If you want to map the numbers 0..4 - call map and then name the argument of the anonymous function you pass i - don't use a var declared outside of the method and expect it to increment
With these corrections (and some more), your version becomes:
val resNum: List[List[Any]] = (0 to 4).map { i =>
List(
aRowcol(i).head.head,
aRowcol(i).head(1),
aAlpha(aRowcol(i).head.head)(aRowcol(i).head(1))) }
.toList
Which works as you expect; But above is a similar yet simpler version.

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 achieve multiple step in scala range

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

How to remove negative numbers from a Seq except the first negative number?

How to remove all negative numbers from a sequence, except the first negative number. I'm not to sure how to keep the first negative number and then remove the other negative numbers.
def negativeNumbers(sequence: Iterable[Int]): Iterable[Int] = {
sequence.filter(_ > 0)
return sequence
}
negativeNumbers(Seq(6, 2, -4, 7, 9, 10, -15, 8, -20))
after execution I should get Seq(6 , 2 , -4 , 7 , 9 , 10 , 8)
Because -4 is the FIRST negative number which means it doesn't get remove, But the other negative numbers get removed.
span gets you close:
scala> val vs = Seq(6, 2, -4, 7, 9, 10, -15, 8, -20)
vs: Seq[Int] = List(6, 2, -4, 7, 9, 10, -15, 8, -20)
scala> val (pos, rest) = vs span (_ >= 0)
pos: Seq[Int] = List(6, 2)
rest: Seq[Int] = List(-4, 7, 9, 10, -15, 8, -20)
scala> (pos :+ rest.head) ++ (rest.tail filter (_ >= 0))
res0: Seq[Int] = List(6, 2, -4, 7, 9, 10, 8)
Edit:
scala> def f(vs: Iterable[Int]) = {
| val (pos, rest) = vs span (_ >= 0)
| (pos ++ rest.headOption) ++ (rest drop 1 filter (_ >= 0))
| }
f: (vs: Iterable[Int])Iterable[Int]
scala> f(List(1,2,3))
res9: Iterable[Int] = List(1, 2, 3)
scala> f(vs)
res10: Iterable[Int] = List(6, 2, -4, 7, 9, 10, 8)
You can do
seq.foldLeft(false -> List.empty[Int]) {
case ((true, ls), neg) if (neg < 0) =>
true -> ls // after firstFound=true
case ((false, ls), neg) if (num < 0) =>
true -> (ls :+ neg)
case ((firstFound, ls), positive) =>
first -> (ls :+ positive)
}._2 // get just List from last state
Split the list into the leading bit with non-negative elements and the rest (which, if non-empty, must start with a negative number). Remove the other negative numbers from the rest
def negativeNumbers(sequence: Iterable[Int]): Iterable[Int] = {
val (before, after) = sequence.span(_>=0)
if (after.isEmpty) before else before ++ Iterable(after.head) ++ after.tail.filter(_>=0)
}
val seq = Seq(6, 2, -4, 7, 9, 10, -15, 8, -20)
val neg = seq.filter{a => a<0}
seq.filter{ b => b>0 || b == neg.headOption.getOrElse(-1)}
My way to do it would be to use scanLeft to track whether the first negative number has been found and then collect the results:
val s = Seq(6, 2, -4, 7, 9, 10, -15, 8, -20)
s.zip(s.scanLeft(true){
(b,i) => b && i >= 0
}).collect{
case (i,b) if b || i >= 0 => i
}