Scala idiom to find first Some of Option from iterator - scala

I have an iterator of Options, and would like to find the first member that is:
Some
and meets a predicate
What's the best idiomatic way to do this?
Also: If an exception is thrown along the way, I'd like to ignore it and move on to the next member

optionIterator find { case Some(x) if predicate(x) => true case _ => false }
As for ignoring exceptions… Is it the predicate that could throw? 'Cause that's not really wise. Nonetheless…
optionIterator find {
case Some(x) => Try(predicate(x)) getOrElse false
case _ => false
}

Adding a coat of best and idiomatic to the paint job:
scala> val vs = (0 to 10) map { case 3 => None case i => Some(i) }
vs: scala.collection.immutable.IndexedSeq[Option[Int]] = Vector(Some(0), Some(1), Some(2), None, Some(4), Some(5), Some(6), Some(7), Some(8), Some(9), Some(10))
scala> def p(i: Int) = if (i % 2 == 0) i > 5 else ???
p: (i: Int)Boolean
scala> import util._
import util._
scala> val it = vs.iterator
it: Iterator[Option[Int]] = non-empty iterator
scala> it collectFirst { case Some(i) if Try(p(i)) getOrElse false => i }
res2: Option[Int] = Some(6)
Getting the first even number over five that doesn't blow up the test.

Assuming that you can wrap your predicate so that any error returns false:
iterator.flatMap(x => x).find(yourSafePredicate)
flatMap takes a collection of collections (which an iterable of Option is as Option and Either are considered collections with a max size of one) and transforms it into a single collection:
scala> for { x <- 1 to 3; y <- 1 to x } yield x :: y :: Nil
res30: IndexedSeq[List[Int]] = Vector(List(1, 1), List(2, 1), List(2, 2), List(3, 1), List(3, 2), List(3, 3))
scala> res30.flatMap(x => x)
res31: IndexedSeq[Int] = Vector(1, 1, 2, 1, 2, 2, 3, 1, 3, 2, 3, 3)
find returns the first entry in your iterable that matches a predicate as an Option or None if there is no match:
scala> (1 to 10).find(_ > 3)
res0: Option[Int] = Some(4)
scala> (1 to 10).find(_ == 11)
res1: Option[Int] = None

Some sample data
scala> val l = Seq(Some(1),None,Some(-7),Some(8))
l: Seq[Option[Int]] = List(Some(1), None, Some(-7), Some(8))
Using flatMap on a Seq of Options will produce a Seq of defined values, all the None's will be discarded
scala> l.flatMap(a => a)
res0: Seq[Int] = List(1, -7, 8)
Then use find on the sequence - you will get the first value, that satisfies the predicate. Pay attention, that found value is wrapped as Option, cause find should be able to return valid value (None) value in case of "not found" situation.
scala> l.flatMap(a => a).find(_ < 0)
res1: Option[Int] = Some(-7)
As far as I know it is "OK" way for the Scala.
Might be more idiomatic way is to use collect / collectFirst on the Seq ...
scala> l.collectFirst { case a#Some(x) if x < 0 => a }
res2: Option[Some[Int]] = Some(Some(-7))
Pay attention that here we have Some(Some(-7)) because the collectFind should have chance to produce "not found" value, so here 1st Some - from collectFirst, the 2nd Some - from the source elements of Seq of Option's.
You can flatten the Some(Some(-7)) if you need the values in your hand.
scala> l.collectFirst({ case a#Some(x) if x < 0 => a }).flatten
res3: Option[Int] = Some(-7)
If nothing found - you will have the None
scala> l.collectFirst({ case a#Some(x) if x < -10 => a }).flatten
res9: Option[Int] = None

Related

scala - swapping first 2 elements in a List

I'm trying to swap first 2 elements in a List using the below function.
def swap_list(a:List[Int]):List[Int]={
a match {
case x::y::Nil => List(y,x)
case List(x,y,rest # _*) => List(y,x)
case _ => a
}
}
swap_list(List(10,20,30))
This works. However, If I try to include the rest I'm getting a error like
case List(x,y,rest # _*) => List(y,x) +: rest
Error below
Error:(27, 50) type mismatch;
found : Seq[Any]
required: List[Int]
case List(x,y,rest # _*) => List(y,x) +: rest
when I'm specifying the function result type in the definition, why am I getting Seq[Any] in the error message?
I need to return List(20,10,30). How to resolve this?.
Apparently operators in scala List are confusing. You need to concat lists using ++,
def swap_list(a:List[Int]):List[Int]={
a match {
case x::y::Nil => List(y,x)
case List(x,y,rest # _*) => List(y,x) ++ rest
case _ => a
}
}
val newList = swap_list(List(10, 20, 30))
println(newList) //List(20, 10, 30)
Summary of List operators,
1) prepend on List using +: or ::
scala> 1000 +: List(1, 2, 3)
res1: List[Int] = List(1000, 1, 2, 3)
scala> 1000 :: List(1, 2, 3)
res4: List[Int] = List(1000, 1, 2, 3)
2) append on List using :+
scala> List(1, 2, 3) :+ 100
res2: List[Int] = List(1, 2, 3, 100)
3) concat Lists using ++, same as in haskell
scala> List(1, 2, 3) ++ List(4, 5, 6)
res3: List[Int] = List(1, 2, 3, 4, 5, 6)
Well, while prayagupd solution works, and clearly explains the problem (and should be the accepted answer IMHO).
I think is worth sharing a "better" solution to this problem, since concatenating lists is expensive, it is better to just prepend elements to them.
def swapList[T](l: List[T]): List[T] = l match {
case Nil => Nil
case x :: Nil => x :: Nil
case x :: y :: xs => y :: x :: xs
}
swapList(List(10,20,30)) // res0: List[Int] = List(20, 10, 30).
You need to ++ instead of +: as the latter is for single element.
The simplest implementation is this:
def swap_list(a: List[Int]): List[Int] =
a match {
case x :: y :: tail => y :: x :: tail
case _ => a
}

Drop a given number of positive items of a given list

Suppose I need a function List[Int] => Option[List[Int]] to drop exactly n elements of a given list if and only if all of them > 0. If the list size <= n the function should return None.
For instance:
def posn(n: Int): List[Int] => Option[List[Int]] = ???
val pos4: List[Int] => Option[List[Int]] = posn(4)
scala> pos4(Nil)
res18: Option[List[Int]] = None
scala> pos4(List(-1))
res19: Option[List[Int]] = None
scala> pos4(List(-1, 2, 3))
res20: Option[List[Int]] = None
scala> pos4(List(1, 2, 3))
res21: Option[List[Int]] = None
scala> pos4(List(1, 2, 3, 4, 5))
res22: Option[List[Int]] = Some(List(5))
scala> pos4(List(1, 2, 3, -4, 5))
res23: Option[List[Int]] = None
I am writing posn like that:
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
if (xs.size >= n && xs.take(n).forall(_ > 0)) Some(xs.drop(n)) else None
This function seems working bit it doesn't seem elegant and idiomatic. How would you re-write it ?
Here's an (arguably) more idiomatic implementation using Pattern Matching and a recursive call to posn - but I'm not sure it's preferable to your suggested implementation:
def posn(n: Int): List[Int] => Option[List[Int]] = xs => (n, xs) match {
case (0, _) => Some(xs) // stop if enough objects dropped
case (_, head :: tail) if head > 0 => posn(n - 1)(tail) // drop positive and move on
case _ => None // found a negative item or end of xs => "fail"
}
I don't know if there is an idiomatic or elegant way to do this. There seems to be no generic pattern that can be extracted from your logic, except what you have already done (using drop and take), so I don't believe you will find some more useful predefined method
However, you are traversing your list a few times, and this could be avoided:
def posn(n: Int): List[Int] => Option[List[Int]] = xs => {
val (head, tail) = xs.splitAt(n) //does take and drop in one run
if (head.lengthCompare(n) == 0 && head.forall(_ > 0)) Some(tail) // lengthCompare does not compute the whole length if there is no need to
else None
}
This is still not perfect, and more verbose than your version.
You could also do all of it at once, with tail recursion (here assuming n>=0):
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
if (n == 0) Some(xs)
else if (xs.isEmpty || xs.head <= 0) None
else posn(n - 1)(xs.tail)
This would be more efficient if List was naively implemented, but I really doubt you will see any improvement.
I would write a generic version and use that to define posn:
def dropWhen[T](n: Int, p: T => Boolean, l: List[T]): Option[List[T]] = {
val (f, s) = l.splitAt(n)
if (f.length >= n && f.forall(p)) { Some(s) } else { None }
}
def posn(n: Int): List[Int] => Option[List[Int]] = l => dropWhen(n, (i : Int) => i > 0, l)
Note this method scans the prefix of length n twice
Another (non-recursive) alternative: use zipWithIndex and dropWhile to drop the first N positive numbers, and then check head to see whether the first remaining item is exactly at position n: if it is, we got what we want, otherwise we can return None:
def posn(n: Int): List[Int] => Option[List[Int]] = xs =>
Some(xs.zipWithIndex.dropWhile { case (v, i) => v > 0 && i < n })
.find(_.headOption.exists(_._2 == n)) // first index should be n
.map(_.map(_._1)) // remove indices

Conditionally adding an Option to a List

If I want to add the value of an Option (should it have one) to a List, is there a better way than:
val x = Some(42)
val xs = List(1,2,3)
val xs2 = x match {
case None => xs
case Some(x2) => x :: xs
}
I know I can use the ++ operator on Iterable like this:
val xs2 = (x ++ xs).toList
But does that explicit conversion back to List cause the entire list to be scanned and copied?
You can use ++: to return a List instead of an Iterable (skipping the .toList call) :
scala> val x = Some(42)
x: Some[Int] = Some(42)
scala> val xs = List(1,2,3)
xs: List[Int] = List(1, 2, 3)
scala> x ++: xs
res4: List[Int] = List(42, 1, 2, 3)
scala> val x = None
x: None.type = None
scala> x ++: xs
res5: List[Int] = List(1, 2, 3)
How about this:
val x: Option[Int] = Some(42)
val xs = List(1,2,3)
val xs2 = xs ++ (x match {
case Some(value) => List(value)
case None => List()
})
Note that I had to tell Scala that x is an Option[Int] so that it wouldn't assume it was a Some[Int] and complain about the matching.

Scala List Operation

Given a List of Int and variable X of Int type . What is the best in Scala functional way to retain only those values in the List (starting from beginning of list) such that sum of list values is less than equal to variable.
This is pretty close to a one-liner:
def takeWhileLessThan(x: Int)(l: List[Int]): List[Int] =
l.scan(0)(_ + _).tail.zip(l).takeWhile(_._1 <= x).map(_._2)
Let's break that into smaller pieces.
First you use scan to create a list of cumulative sums. Here's how it works on a small example:
scala> List(1, 2, 3, 4).scan(0)(_ + _)
res0: List[Int] = List(0, 1, 3, 6, 10)
Note that the result includes the initial value, which is why we take the tail in our implementation.
scala> List(1, 2, 3, 4).scan(0)(_ + _).tail
res1: List[Int] = List(1, 3, 6, 10)
Now we zip the entire thing against the original list. Taking our example again, this looks like the following:
scala> List(1, 2, 3, 4).scan(0)(_ + _).tail.zip(List(1, 2, 3, 4))
res2: List[(Int, Int)] = List((1,1), (3,2), (6,3), (10,4))
Now we can use takeWhile to take as many values as we can from this list before the cumulative sum is greater than our target. Let's say our target is 5 in our example:
scala> res2.takeWhile(_._1 <= 5)
res3: List[(Int, Int)] = List((1,1), (3,2))
This is almost what we want—we just need to get rid of the cumulative sums:
scala> res2.takeWhile(_._1 <= 5).map(_._2)
res4: List[Int] = List(1, 2)
And we're done. It's worth noting that this isn't very efficient, since it computes the cumulative sums for the entire list, etc. The implementation could be optimized in various ways, but as it stands it's probably the simplest purely functional way to do this in Scala (and in most cases the performance won't be a problem, anyway).
In addition to Travis' answer (and for the sake of completeness), you can always implement these type of operations as a foldLeft:
def takeWhileLessThanOrEqualTo(maxSum: Int)(list: Seq[Int]): Seq[Int] = {
// Tuple3: the sum of elements so far; the accumulated list; have we went over x, or in other words are we finished yet
val startingState = (0, Seq.empty[Int], false)
val (_, accumulatedNumbers, _) = list.foldLeft(startingState) {
case ((sum, accumulator, finished), nextNumber) =>
if(!finished) {
if (sum + nextNumber > maxSum) (sum, accumulator, true) // We are over the sum limit, finish
else (sum + nextNumber, accumulator :+ nextNumber, false) // We are still under the limit, add it to the list and sum
} else (sum, accumulator, finished) // We are in a finished state, just keep iterating over the list
}
accumulatedNumbers
}
This only iterates over the list once, so it should be more efficient, but is more complicated and requires a bit of reading code to understand.
I will go with something like this, which is more functional and should be efficient.
def takeSumLessThan(x:Int,l:List[Int]): List[Int] = (x,l) match {
case (_ , List()) => List()
case (x, _) if x<= 0 => List()
case (x, lh :: lt) => lh :: takeSumLessThan(x-lh,lt)
}
Edit 1 : Adding tail recursion and implicit for shorter call notation
import scala.annotation.tailrec
implicit class MyList(l:List[Int]) {
def takeSumLessThan(x:Int) = {
#tailrec
def f(x:Int,l:List[Int],acc:List[Int]) : List[Int] = (x,l) match {
case (_,List()) => acc
case (x, _ ) if x <= 0 => acc
case (x, lh :: lt ) => f(x-lh,lt,acc ++ List(lh))
}
f(x,l,Nil)
}
}
Now you can use this like
List(1,2,3,4,5,6,7,8).takeSumLessThan(10)

How can I find the index of the maximum value in a List in Scala?

For a Scala List[Int] I can call the method max to find the maximum element value.
How can I find the index of the maximum element?
This is what I am doing now:
val max = list.max
val index = list.indexOf(max)
One way to do this is to zip the list with its indices, find the resulting pair with the largest first element, and return the second element of that pair:
scala> List(0, 43, 1, 34, 10).zipWithIndex.maxBy(_._1)._2
res0: Int = 1
This isn't the most efficient way to solve the problem, but it's idiomatic and clear.
Since Seq is a function in Scala, the following code works:
list.indices.maxBy(list)
even easier to read would be:
val g = List(0, 43, 1, 34, 10)
val g_index=g.indexOf(g.max)
def maxIndex[ T <% Ordered[T] ] (list : List[T]) : Option[Int] = list match {
case Nil => None
case head::tail => Some(
tail.foldLeft((0, head, 1)){
case ((indexOfMaximum, maximum, index), elem) =>
if(elem > maximum) (index, elem, index + 1)
else (indexOfMaximum, maximum, index + 1)
}._1
)
} //> maxIndex: [T](list: List[T])(implicit evidence$2: T => Ordered[T])Option[Int]
maxIndex(Nil) //> res0: Option[Int] = None
maxIndex(List(1,2,3,4,3)) //> res1: Option[Int] = Some(3)
maxIndex(List("a","x","c","d","e")) //> res2: Option[Int] = Some(1)
maxIndex(Nil).getOrElse(-1) //> res3: Int = -1
maxIndex(List(1,2,3,4,3)).getOrElse(-1) //> res4: Int = 3
maxIndex(List(1,2,2,1)).getOrElse(-1) //> res5: Int = 1
In case there are multiple maximums, it returns the first one's index.
Pros:You can use this with multiple types, it goes through the list only once, you can supply a default index instead of getting exception for empty lists.
Cons:Maybe you prefer exceptions :) Not a one-liner.
I think most of the solutions presented here go thru the list twice (or average 1.5 times) -- Once for max and the other for the max position. Perhaps a lot of focus is on what looks pretty?
In order to go thru a non empty list just once, the following can be tried:
list.foldLeft((0, Int.MinValue, -1)) {
case ((i, max, maxloc), v) =>
if (v > max) (i + 1, v, i)
else (i + 1, max, maxloc)}._3
Pimp my library! :)
class AwesomeList(list: List[Int]) {
def getMaxIndex: Int = {
val max = list.max
list.indexOf(max)
}
}
implicit def makeAwesomeList(xs: List[Int]) = new AwesomeList(xs)
//> makeAwesomeList: (xs: List[Int])scalaconsole.scratchie1.AwesomeList
//Now we can do this:
List(4,2,7,1,5,6) getMaxIndex //> res0: Int = 2
//And also this:
val myList = List(4,2,7,1,5,6) //> myList : List[Int] = List(4, 2, 7, 1, 5, 6)
myList getMaxIndex //> res1: Int = 2
//Regular list methods also work
myList filter (_%2==0) //> res2: List[Int] = List(4, 2, 6)
More details about this pattern here: http://www.artima.com/weblogs/viewpost.jsp?thread=179766