How to break early when foldLeft over simple List? - scala

This is a simplified version of my problem, I want to stop the fold return the value after the if condition is met in the fold where a.size == 7.
class test1 {
def test(a : List[Int]): Int = {
val list = a.foldLeft(if(a.size == 7) 1000 else 0)((b,a) => a + b )
list
}
}
object test1 extends App{
val temp1 = new test1()
val list: List[Int] = List(1,2,3,4,5,6,7)
println(temp1.test(list))
}
As you can see the condition is met on the first fold, but there are cases where it can be met on the second or first. Not sure where to go from here any help with be appreciated

Try next template:
def Process(A: List[Int]) : Int = {
def proces(a: List[Int], acc: List[Int]): Int = a match {
case List () => -1
case h :: tail => if (acc.length == 10) 1000 else proces (tail, h :: acc)
}
proces(A, List() )
}

Related

Improve Two sum problem using Map in scala

I am trying to solve Two sum problem using scala
val list = List(1,2,3,4,5)
val map = collection.mutable.Map.empty[Int, Int]
val sum = 9
for {
i <- 0 until list.size
} yield {
map.get(sum - list(i)) match {
case None => map += (list(i) -> i)
case Some(previousIndex) => println(s" Indexes $previousIndex $i")
}
}
Can anyone suggest an O(n) solution without using mutable map using scala
If you are trying to solve "Two sum problem" - meaning you need from given list find two numbers which gives sum equal to given, can go with:
val list = List(1,2,3,4,5)
val sum = 9
val set = list.toSet
val solution = list.flatMap { item =>
val rest = sum - item
val min = Math.min(item, rest)
val max = Math.max(item, rest)
if (set(rest)) Some(min, max) else None
}.toSet
println(solution)
Print result:
Set((4,5))
ScalaFiddle: https://scalafiddle.io/sf/LA6P3eh/0
UPDATE
The result required to return indices not values:
val list = List(1,2,3,4,5)
val sum = 9
val inputMap = list.zipWithIndex.toMap
val solution = list.zipWithIndex.flatMap { case (item, itemIndex) =>
inputMap.get(sum - item).map { restIndex =>
val minIndex = Math.min(itemIndex, restIndex)
val maxIndex = Math.max(itemIndex, restIndex)
minIndex -> maxIndex
}
}.toSet
println(solution)
Printout: Set((3,4))
ScalaFiddle: https://scalafiddle.io/sf/LA6P3eh/1
You can try something as follows for the first result:
object Solution extends App {
def twoSums(xs: List[Int], target: Int): Option[(Int,Int)] = {
#annotation.tailrec def go(zipped: List[(Int,Int)], map: Map[Int,Int] = Map.empty): Option[(Int,Int)] = {
zipped match {
case Nil => None
case (ele, idx) :: tail =>
map.get(target - ele) match {
case Some(prevIdx) => Some((prevIdx, idx))
case None => go(tail, map + (ele -> idx))
}
}
}
go(xs.zipWithIndex)
}
val res = twoSums(List(1,2,3,4,5), 9)
println(res)
}
Or via foldLeft for all results:
object Solution extends App {
def twoSums(xs: List[Int], target: Int): List[(Int, Int)] = {
xs.zipWithIndex.foldLeft((Map.empty[Int,Int], List.empty[(Int,Int)])) {
case ((map, results), (ele, idx)) =>
map.get(target - ele) match {
case Some(prevIdx) =>(map, (prevIdx, idx) :: results)
case None => (map + (ele -> idx), results)
}
}
}._2
val res = twoSums(List(1,2,3,4,5), 9)
println(res)
}

Scala apply function on list elements to return a value

I have found this answer in the forum earlier to a question I have been looking for, How to find a matching element in a list and map it in as an Scala API method?
// Returns Some(66)
List(1, 2, 3) collectFirst { case i if (i * 33 % 2 == 0) => i * 33 }
Now if I am replacing the if clause with a function
//
List(1, 2, 3) collectFirst { case i if ( test(i) > 0) => test(i) }
this works but test() will be evaluated twice. Is there a better solution to apply a function to a list and return a result when a condition is met (not having to go through all elements and not havong to call the function twice (for evaluation and for returning the value.
Something like this, perhaps?
Breaking it into two separate operations lets you save/reuse intermediate results.
List(1,2,3).iterator.map(test).find(_ > 0)
You can wrap your function in a custom extractor:
def test(i: Int): Int = i - 1
object Test {
def unapply(i: Int): Option[Int] = Some(test(i))
}
scala> List(1, 10, 20) collectFirst { case Test(i) if i > 0 => i }
res0: Option[Int] = Some(9)
You can generalize this solution and make a class for that kind of extractors:
case class Extract[T, U](f: T => U) {
def unapply(t: T): Option[U] = Some(f(t))
}
scala> val Test2 = Extract(test)
Test2: Extract[Int,Int] = Extract($$Lambda$1326/1843609566#69c33ea2)
scala> List(1, 10, 20) collectFirst { case Test2(i) if i > 0 => i }
res1: Option[Int] = Some(9)
You can also wrap the guard into the extractor as well:
case class ExtractWithGuard[T, U](f: T => U)(pred: U => Boolean) {
def unapply(t: T): Option[U] = {
val u = f(t)
if (pred(u)) Some(u)
else None
}
}
scala> val Test3 = ExtractWithGuard(test)(_ > 0)
Test3: ExtractWithGuard[Int,Int] = ExtractWithGuard($$Lambda$1327/391731126#591a4d25)
scala> List(1, 10, 20) collectFirst { case Test3(i) => i }
res2: Option[Int] = Some(9)

I am trying to implement a recursive function in Scala to calculate Maximum value in a List

def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new java.util.NoSuchElementException("List is Empty")
else
max1(0,xs)
def max1(num :Int, x : List[Int]) : Int = {
if(x.isEmpty) return num
else if(num>x.head) max1(num,x.tail)
else
max1(x.head,x.tail)
}
}
I am trying to Implement code to throw error when it gets an empty list as input and trying to get the maximum value of the list in a recursive way using another helper function
error: type mismatch; found : Unit required: Int
Put the definition of max1 before the if statement.
The return value of a function is the result of the last statement in its body. The way you have it now, the last statement is def, and it's result is Unit.
You can use user require()
For example with this more idiomatic recursion code:
def max(xs: List[Int]): Int = {
require( xs.nonEmpty, ">>> Empty List <<<" )
def max1( num:Int, x:List[Int] ) : Int = x match {
case Nil => num
case y :: ys => max1( (if( num>y ) num else y), ys )
}
max1(0,xs)
}
Then,
max(List())
returns: java.lang.IllegalArgumentException: requirement failed: >>> Empty List <<<
You can use these code to solve that problem.
object Maximum {
def apply(numbers: List[Int]): Int = {
if (numbers.isEmpty) throw new Exception("List shouldn't be empty")
max(numbers)
}
private def max(numbers: List[Int], maxNumb: Int = 0): Int = numbers match {
case x::xs => if (x > maxNumb) max(xs, x) else max(xs, maxNumb)
case Nil => maxNumb
}
}
Maximum(List(1,9,9,12,34))
Maximum(List())
Define
trait XInt
case class N(i: Int) extends XInt
case object NoInt extends XInt
and on pattern-matching an empty list return NoInt and otherwise an N instance.

Structure to allow #tailrec when multiple recursive calls are invoked

The following logic identifies the combination of integers summing to n that produces the maximum product:
def bestProd(n: Int) = {
type AType = (Vector[Int], Long)
import annotation._
// #tailrec (umm .. nope ..)
def bestProd0(n: Int, accum : AType): AType = {
if (n<=1) accum
else {
var cmax = accum
for (k <- 2 to n) {
val tmpacc = bestProd0(n-k, (accum._1 :+ k, accum._2 * k))
if (tmpacc._2 > cmax._2) {
cmax = tmpacc
}
}
cmax
}
}
bestProd0(n, (Vector(), 1))
}
This code does work:
scala> bestProd(11)
res22: (Vector[Int], Long) = (Vector(2, 3, 3, 3),54)
Now it was not a surprise to me that #tailrec did not work. After all the recursive invocation is not in the tail position. Is is possible to reformulate the for loop to instead do a proper single-call to achieve the tail recursion?
I don't think it's possible if you're trying to stick close to the stated algorithm. Rethinking the approach you could do something like this.
import scala.annotation.tailrec
def bestProd1(n: Int) = {
#tailrec
def nums(acc: Vector[Int]): Vector[Int] = {
if (acc.head > 4)
nums( (acc.head - 3) +: 3 +: acc.tail )
else
acc
}
val result = nums( Vector(n) )
(result, result.product)
}
It comes up with the same results (as far as I can tell) except for I don't split 4 into 2,2.

Cartesian product stream scala

I had a simple task to find combination which occurs most often when we drop 4 cubic dices an remove one with least points.
So, the question is: are there any Scala core classes to generate streams of cartesian products in Scala? When not - how to implement it in the most simple and effective way?
Here is the code and comparison with naive implementation in Scala:
object D extends App {
def dropLowest(a: List[Int]) = {
a diff List(a.min)
}
def cartesian(to: Int, times: Int): Stream[List[Int]] = {
def stream(x: List[Int]): Stream[List[Int]] = {
if (hasNext(x)) x #:: stream(next(x)) else Stream(x)
}
def hasNext(x: List[Int]) = x.exists(n => n < to)
def next(x: List[Int]) = {
def add(current: List[Int]): List[Int] = {
if (current.head == to) 1 :: add(current.tail) else current.head + 1 :: current.tail // here is a possible bug when we get maximal value, don't reuse this method
}
add(x.reverse).reverse
}
stream(Range(0, times).map(t => 1).toList)
}
def getResult(list: Stream[List[Int]]) = {
list.map(t => dropLowest(t).sum).groupBy(t => t).map(t => (t._1, t._2.size)).toMap
}
val list1 = cartesian(6, 4)
val list = for (i <- Range(1, 7); j <- Range(1,7); k <- Range(1, 7); l <- Range(1, 7)) yield List(i, j, k, l)
println(getResult(list1))
println(getResult(list.toStream) equals getResult(list1))
}
Thanks in advance
I think you can simplify your code by using flatMap :
val stream = (1 to 6).toStream
def cartesian(times: Int): Stream[Seq[Int]] = {
if (times == 0) {
Stream(Seq())
} else {
stream.flatMap { i => cartesian(times - 1).map(i +: _) }
}
}
Maybe a little bit more efficient (memory-wise) would be using Iterators instead:
val pool = (1 to 6)
def cartesian(times: Int): Iterator[Seq[Int]] = {
if (times == 0) {
Iterator(Seq())
} else {
pool.iterator.flatMap { i => cartesian(times - 1).map(i +: _) }
}
}
or even more concise by replacing the recursive calls by a fold :
def cartesian[A](list: Seq[Seq[A]]): Iterator[Seq[A]] =
list.foldLeft(Iterator(Seq[A]())) {
case (acc, l) => acc.flatMap(i => l.map(_ +: i))
}
and then:
cartesian(Seq.fill(4)(1 to 6)).map(dropLowest).toSeq.groupBy(i => i.sorted).mapValues(_.size).toSeq.sortBy(_._2).foreach(println)
(Note that you cannot use groupBy on Iterators, so Streams or even Lists are the way to go whatever to be; above code still valid since toSeq on an Iterator actually returns a lazy Stream).
If you are considering stats on the sums of dice instead of combinations, you can update the dropLowest fonction :
def dropLowest(l: Seq[Int]) = l.sum - l.min