Scala way of if else with two conditional variables - scala

I have a the following Java snippet (where a and b are futures):
if (a.isEmpty && b.isEmpty) func(list)
else if (a.isEmpty) func(list, b)
else if (b.isEmpty) func(a, list)
else func(a, list, b)
I have all the implementations of the function 'func'.
Is there a proper way to write this in Scala or is this good enough?

Assuming a and b are lists, which seems likely as they seem related to list:
(a, b) match {
case (Nil, Nil) => func(list)
case (Nil, _) => func(list, b)
case (_, Nil) => func(a, list)
case _ => func(a, b, list)
}

Related

Scala - Use predicate function to summarize list of strings

I need to write a function to analyze some text files.
For that, there should be a function that splits the file via a predicate into sublists. It should only get the values after the first time the predicate evaluates to True and afterwards start a new sublist after the predicate was True again.
For Example:
List('ignore','these','words','x','this','is','first','x','this','is','second')
with predicate
x=>x.equals('x')
should produce
List(List('this','is','first'),List('this','is','second'))
I've already done the reading of the file into a List[String] and tried to use foldLeft with a case statement to iterate over the List.
words.foldLeft(List[List[String]]()) {
case (Nil, s) => List(List(s))
case (result, "x") => result :+ List()
case (result, s) => result.dropRight(1) :+ (result.last :+ s)
}
There are 2 problems with this though and I can't figure them out:
This does not ignore the words before the first time the predicate
evaluates to True
I can't use an arbitrary predicate function
If anyone could tell me what I have to do to fix my problems it would be highly appreciated.
I modified your example a little bit:
def foldWithPredicate[A](predicate: A => Boolean)(l: List[A]) =
l.foldLeft[List[List[A]]](Nil){
case (acc, e) if predicate(e) => acc :+ Nil //if predicate passed add new list at the end
case (Nil, _) => Nil //empty list means we need to ignore elements
case (xs :+ x, e) => xs :+ (x :+ e) //append an element to the last list
}
val l = List("ignore","these","words","x","this","is","first","x","this","is","second")
val predicate: String => Boolean = _.equals("x")
foldWithPredicate(predicate)(l) // List(List(this, is, first), List(this, is, second))
There's one problem performance related to your approach: appending is very slow on immutable lists.
It might be faster to prepend elements on the list, but then, of course, all lists will have elements in reversed order (but they could be reversed at the end).
def foldWithPredicate2[A](predicate: A => Boolean)(l: List[A]) =
l.foldLeft[List[List[A]]](Nil){
case (acc, e) if predicate(e) => Nil :: acc
case (Nil, _) => Nil
case (x :: xs, e) => (e :: x) :: xs
}.map(_.reverse).reverse
An alternative approach is to use span to split the items into the next sublist and the rest in a single call. The following code assumes Scala 2.13 for List.unfold:
def splitIntoBlocks[T](items: List[T])(startsNewBlock: T => Boolean): List[List[T]] = {
def splitBlock(items: List[T]): (List[T], List[T]) = items.span(!startsNewBlock(_))
List.unfold(splitBlock(items)._2) {
case blockIndicator :: rest => Some(splitBlock(rest))
case _ => None
}
}
And the usage:
scala> splitIntoBlocks(List(
"ignore", "these", "words",
"x", "this", "is", "first",
"x", "this", "is", "second")
)(_ == "x")
res0: List[List[String]] = List(List(this, is, first), List(this, is, second))

Scala method optimization

I'm having a def that is recursively called and I'm using a bunch of cases.
I'm wondering is there is any nice solution to get rid of that cases, without losing the readability of the definition.
#tailrec
def getElements(existent:List[List[String]], proposed: List[List[String]], result: List[(String,List[String])]): List[(String, List[String])]= {
proposed match {
case head :: tail => {
existent.find(element => identicalOfMatch(element, head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail, ("Same", elem) :: result)
case None => {
existent.find(element => noneOfMatch(element, head) && canDelete(proposed, element)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), head::tail, ("Delete", elem) :: result)
case None => {
existent.find(element => firstOfMatch(element, head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail, ("Update", head) :: result)
case None => {
existent.find(element => anyOfMatch(element, head) && firstOfNotPresent(proposed, head.head) && firstOfNotPresent(existent, head.head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail, ("Update", head) :: result)
case None => getElements(Nil, Nil, existent.map(element => ("Deleted", element)) ::: proposed.map(element => ("Created", element)) ::: result)
}
}
}
}
}
}
}
}
case Nil => result
}
}
Your method readability would benefit greatly if you could split it into several methods.
Unfortunately, you can't do that if you want your function to be tail-recursive.
But there is a solution which is called trampoline, which would allow you to create an arbitrarily deep chain of function recursive calls which are stack-safe.
Trampolines are implemented in Scala standard library in package scala.util.control.TailCalls. I reimplemented your method to take advantage of it.
First thing I did was removing an accumulator parameter from getElements, we won't need it anymore.
Then I split getElements into three functions. I called nested functions ifNoneMatched and ifNoneMatched2 but you could probably come up with more meaningful names.
Then I wrapped every call to a function which is in the chain into tailcall and every constant into done (in our case Nil). When I needed to append something to list returned from a recursive call I used flatMap from TailRec.
import scala.util.control.TailCalls._
def getElements(existent:List[List[String]], proposed: List[List[String]]): TailRec[List[(String, List[String])]]= {
proposed match {
case head :: tail => {
existent.find(element => identicalOfMatch(element, head)) match {
case Some(elem) => tailcall(getElements(existent.filterNot(e => e == elem), tail).map(("Same", elem) :: _))
case None => tailcall(ifNoneMatched(head, tail, existent, proposed))
}
}
case Nil => done(Nil)
}
}
def ifNoneMatched(head: List[String], tail: List[List[String]], existent:List[List[String]], proposed: List[List[String]]): TailRec[List[(String, List[String])]] = {
existent.find(element => noneOfMatch(element, head) && canDelete(proposed, element)) match {
case Some(elem) => tailcall(getElements(existent.filterNot(e => e == elem), proposed)).map(("Delete", elem) :: _)
case None => tailcall(ifNoneMatched2(head, tail, existent, proposed))
}
}
def ifNoneMatched2(head: List[String], tail: List[List[String]], existent:List[List[String]], proposed: List[List[String]]): TailRec[List[(String, List[String])]] = {
existent.find(element => firstOfMatch(element, head)) match {
case Some(elem) => getElements(existent.filterNot(e => e == elem), tail).map(("Update", head) :: _)
case None => {
existent.find(element => anyOfMatch(element, head) && firstOfNotPresent(proposed, head.head) && firstOfNotPresent(existent, head.head)) match {
case Some(elem) => tailcall(getElements(existent.filterNot(e => e == elem), tail)).map(("Update", head) :: _)
case None => getElements(Nil, Nil).map(existent.map(element => ("Deleted", element)) ::: proposed.map(element => ("Created", element)) ::: _)
}
}
}
}
getElements returns now TailRec[List[(String, List[String])]], but you can unwrap it by just calling result.
Of course, you can nest methods even deeper. Until you wrap your method calls into tailcall your stack is safe.
I didn't reimplement your methods like identicalOfMatch etc. so I couldn't really test if my implementation works. If something breaks please let me know ;)

how can I write a function in scala called Order that takes one arguement: a list of Ints. And returns the same List of Ints from least to greatest

I've got a base case and a recursive call but I don't know where to go from there.I do also need to use pattern matching
def order(ls:List[Int]):List[Int] = ls match {
case Nil => Nil
case h::t => order(t)
I'm pretty sure you are looking for a recursive sort algorithm.
You can take a look at merge sort for example. This is a simplified Non generic version
def mergeSort(ls: List[Int]): List[Int] = {
def merge(l: List[Int], r: List[Int]): List[Int] = (l, r) match {
case (Nil, _) => r
case (_, Nil) => l
case (lHead :: lTail, rHead :: rTail) =>
if (lHead < rHead) {
lHead :: merge(lTail, r)
} else {
rHead :: merge(l, rTail)
}
}
val n = ls.length / 2
if (n == 0)
ls
else {
val (a, b) = ls splitAt n
merge(mergeSort(a), mergeSort(b))
}
}
Try This
def order(ls:List[Int]):List[Int] = ls match {
case Nil => Nil
case h => h.sorted
}
OR
def order(ls:List[Int]):List[Int] = ls match {
case Nil => Nil
case h => h.sortWith(_ < _)
}

Implementing `elem` with foldLeft

I'm working on Learn You a Haskell. On the "fold" section, I need to implement elem (given an element, find out if it's in the list - True or False).
def myElem(a: Char, as: List[Char]): Boolean = as match {
case Nil => false
case x::Nil => println(x); if(x == a) true else false
case x::_ => println(x); as.foldLeft(false){ (_, elem) =>
if(a == elem) true
else myElem(a, as.tail)
}
}
However, it's failing on a simple example:
scala> myElem('a', "ab".toList)
a
b
res8: Boolean = false
What am I doing wrong here? Also, as extra, I'd appreciate any suggestion on improvement of this code.
As an aside, I would think a find would be more appropriate here.
This is a pretty simple implementation:
def elem[A](a: A, as: List[A]): Boolean = as match {
case Nil => false
case h :: t => (h == a) || elem(a, t)
}
Also, instead of find you could use exists:
def elem[A](a: A, as: List[A]) = as.exists(_ == a)
If you want to foldLeft you can, but you'll still traverse the whole list instead of stopping early:
def elem[A](a: A, as: List[A]) =
as.foldLeft(false)((bool, value) => bool || value == a)

Checking Members for Nil

Let's say I have a Tree object with 2 member objects, right and left.
What's the idiomatic/right way to check if tree's "right" and "left" fields are Nil?
def count(tree: Tree, acc: Int) : Int = tree match {
case tree .right != Nil && tree .left != Nil => countLeftAndRight(...)
case tree .right != Nil => countOnlyRight(...)
case tree .left != Nil => countOnlyLeft(...)
_ => acc
}
Your example isn't valid Scala, but the idiomatic way to match the Tree is with an extractor (look it up). You get this for free if Tree is a case class. Assuming it is, you can write
tree match {
case Tree(Nil, Nil) => acc
case Tree(Nil, x) => ...
case Tree(x, Nil) => ...
case Tree(x, y) => ...
}
Or, if you'd prefer to work with your non-case-class Tree as-is, then you might try this variation of Luigi's solution:
(tree.left, tree.right) match {
case (Nil, Nil) => acc
case (Nil, x) => ...
case (x, Nil) => ...
case (x, y) => ...