There is a good question which says that we should Stream/View or Iterate our collections to make them on-demand. It is clear. I just do not understand what should I apply the .view or .iterate to in the following demo
val l1 = List("10", "00", "0")
def gen(depth: Int): Iterable[String] = if (depth == 1) l1 else {
for (sub <- gen(depth-1); item <- List(depth + sub, sub+sub, sub)) yield item
}
Should I apply them to gen(depth-1) or to List(depth+..)?
By the way, should I inline l1 in the (depth == 1) l1 else? It is not used anywhere else. I just afraid that it would create a new list for every leaf.
I would have to try it, but I would say List(depth+..).view, since you wont use the same values more than once.I think it will give you a sort of DFS traversal given the recursion you have there.
And yeah, I would not inline it but live l1 like that. I would even do val l1 = List("10", "00", "0").view.
Related
Sorry if this is a stupid question as I am a total beginner. I have a function factors which looks like this:
def factors (n:Int):List[Int] = {
var xs = List[Int]()
for(i <- 2 to (n-1)) {
if(n%i==0) {xs :+ i}
}
return xs
}
However if I do println(factors(10)) I always get List().
What am I doing wrong?
The :+ operation returns a new List, you never assign it to xs.
def factors (n:Int):List[Int] = {
var xs = List[Int]()
for (i <- 2 to (n - 1)) {
if(n%i==0) {xs = xs :+ i}
}
return xs
}
But, you really shouldn't be using var. We don't like them very much in Scala.
Also don't don't don't use return in Scala. It is a much more loaded keyword than you might think. Read about it here
Here is a better way of doing this.
def factors (n:Int): List[Int] =
for {
i <- (2 to (n - 1)).toList
if (n % i) == 0
} yield i
factors(10)
You don't need .toList either but didn't want to mess with your return types. You are welcome to adjust
Working link: https://scastie.scala-lang.org/haGESfhKRxqDdDIpaHXfpw
You can think of this problem as a filtering operation. You start with all the possible factors and you keep the ones where the remainder when dividing the input by that number is 0. The operation that does this in Scala is filter, which keeps values where a particular test is true and removes the others:
def factors(n: Int): List[Int] =
(2 until n).filter(n % _ == 0).toList
To keep the code short I have also used the short form of a function where _ stands for the argument to the function, so n % _ means n divided by the current number that is being tested.
Say I have
val l1 = List(1,2,3,4)
val l2 = List(True,False,False,True)
I want to filter elements of l1 that corresponds to True elements in l2
I have done the following:
type Predicate[T] = T => Boolean
def filterXbasedOnY[A, B](X: List[A], Y: List[B], p: Predicate[B]): List[A] = {
{
for {i <- 0 until Y.size if p(Y(i))} yield X(i)
}.toList
}
which is working fine by calling:
val result = filterXbasedOnY(l1, l2, (b:Boolean) => b)
but is this the best way to accomplish this?
List(1, 2, 3, 4).zip(List(true, false, false, true)).filter(_._2).map(_._1)
As suggested by #C4stor, if the idea is to broaden the usage of the filtering to different types, I think we can reduce the complexity (I use toMatch: B in the following to simplify, but the Predicate can still be used):
def filter[A, B](l1: List[A], l2: List[B], toMatch: B): List[A] = {
l1.zip(l2).filter(_._2 == toMatch).map(_._1)
}
The pipeline would thus be O(n) while keeping working with List objects. Otherwise, calling p(Y(i)) on a List n times would be O(n2).
As specified by #C4stor, and as it's already the case with your solution, it handles l1 being shorter than l2.
filter(List("1", "2", "3"), List("True", "False", "True", "False"), "True") // List(1, 3)
I don't know if it's the best way, but it's at least a good way :
It's easy to read, and explicit
It handles l2 not being booleans, it can easily be fixed to handle correctly X being a smaller size than Y
It's well contained and easy to test
None of the proposed one liners have those desirable properties, so, kudos to you, well done ! You're solution is actually, in my opinion, on the way to be the prod ready version of the proposed one liners.
Btw, may I suggest to you the codereview stackexchange for codereview style questions ?
For syntax might make it more readable, and the use of a filterFunction means that l2 can be whatever type it needs to be.
for( (l1,l2) <- (list1 zip list2) if (filterFunction(l2))) yield l1
I have two lists one is:
val l1 = List[Either[A,B]]
and
val l2 = List[String]
Now, all I need to do is map these two. i.e., if l1 is A then return corresponding value from l2. Tried something like:
for {
elem1 <- l1
elem2 <- l2
result <- if(elem1.isLeft) url
} yield result
This doesn't work. Because, I am not handling the else case. Similarly with match instead of if. How do I go about to achieve this?
You could do something like this (I'm assuming l2 has at least the same number of elements of type A as Lefts in l1):
val result: List[String] = l1.zip(l2).filter(_._1.isLeft).map(_._2)
Otherwise, if you prefer using for, this will also do the trick:
scala> for {
| e1 <- l1.zip(l2)
| if e1._1.isLeft
| } yield e1._2
Simply, I have two lists and I need to extract the new elements added to one of them.
I have the following
val x = List(1,2,3)
val y = List(1,2,4)
val existing :List[Int]= x.map(xInstance => {
if (!y.exists(yInstance =>
yInstance == xInstance))
xInstance
})
Result :existing: List[AnyVal] = List((), (), 3)
I need to remove all other elements except the numbers with the minimum cost.
Pick a suitable data structure, and life becomes a lot easier.
scala> x.toSet -- y
res1: scala.collection.immutable.Set[Int] = Set(3)
Also beware that:
if (condition) expr1
Is shorthand for:
if (condition) expr1 else ()
Using the result of this, which will usually have the static type Any or AnyVal is almost always an error. It's only appropriate for side-effects:
if (condition) buffer += 1
if (condition) sys.error("boom!")
retronym's solution is okay IF you don't have repeated elements that and you don't care about the order. However you don't indicate that this is so.
Hence it's probably going to be most efficient to convert y to a set (not x). We'll only need to traverse the list once and will have fast O(log(n)) access to the set.
All you need is
x filterNot y.toSet
// res1: List[Int] = List(3)
edit:
also, there's a built-in method that is even easier:
x diff y
(I had a look at the implementation; it looks pretty efficient, using a HashMap to count ocurrences.)
The easy way is to use filter instead so there's nothing to remove;
val existing :List[Int] =
x.filter(xInstance => !y.exists(yInstance => yInstance == xInstance))
val existing = x.filter(d => !y.exists(_ == d))
Returns
existing: List[Int] = List(3)
I have been looking into recursion and TCO. It seems that TCO can make the code verbose and also impact the performance. e.g. I have implemented the code which takes in 7 digit phone number and gives back all possible permutation of words e.g. 464-7328 can be "GMGPDAS ... IMGREAT ... IOIRFCU" Here is the code.
/*Generate the alphabet table*/
val alphabet = (for (ch <- 'a' to 'z') yield ch.toString).toList
/*Given the number, return the possible alphabet List of String(Instead of Char for convenience)*/
def getChars(num : Int) : List[String] = {
if (num > 1) return List[String](alphabet((num - 2) * 3), alphabet((num - 2) * 3 + 1), alphabet((num - 2) * 3 + 2))
List[String](num.toString)
}
/*Recursion without TCO*/
def getTelWords(input : List[Int]) : List[String] = {
if (input.length == 1) return getChars(input.head)
getChars(input.head).foldLeft(List[String]()) {
(l, ch) => getTelWords(input.tail).foldLeft(List[String]()) { (ll, x) => ch + x :: ll } ++ l
}
}
It is short and I don't have to spend too much time on this. However when I try to do that in tail call recursion to get it TCO'ed. I have to spend a considerable amount of time and The code become very verbose. I won't be posing the whole code to save space. Here is a link to git repo link. It is for sure that quite a lot of you can write better and concise tail recursive code than mine. I still believe that in general TCO is more verbose (e.g. Factorial and Fibonacci tail call recursion has extra parameter, accumulator.) Yet, TCO is needed to prevent the stack overflow. I would like to know how you would approach TCO and recursion. The Scheme implementation of Akermann with TCO in this thread epitomize my problem statement.
Is it possible that you're using the term "tail call optimization", when in fact you really either mean writing a function in iterative recursive style, or continuation passing style, so that all the recursive calls are tail calls?
Implementing TCO is the job of a language implementer; one paper that talks about how it can be done efficiently is the classic Lambda: the Ultimate GOTO paper.
Tail call optimization is something that your language's evaluator will do for you. Your question, on the other hand, sounds like you are asking how to express functions in a particular style so that the program's shape allows your evaluator to perform tail call optimization.
As sclv mentioned in the comments, tail recursion is pointless for this example in Haskell. A simple implementation of your problem can be written succinctly and efficiently using the list monad.
import Data.Char
getChars n | n > 1 = [chr (ord 'a' + 3*(n-2)+i) | i <- [0..2]]
| otherwise = ""
getTelNum = mapM getChars
As said by others, I would not be worried about tail call for this case, as it does not recurse very deeply (length of the input) compared to the size of the output. You should be out of memory (or patience) before you are out of stack
I would implement probably implement with something like
def getTelWords(input: List[Int]): List[String] = input match {
case Nil => List("")
case x :: xs => {
val heads = getChars(x)
val tails = getTelWords(xs)
for(c <- heads; cs <- tails) yield c + cs
}
}
If you insist on a tail recursive one, that might be based on
def helper(reversedPrefixes: List[String], input: List[Int]): List[String]
= input match {
case Nil => reversedPrefixes.map(_.reverse)
case (x :: xs) => helper(
for(c <- getChars(x); rp <- reversedPrefixes) yield c + rp,
xs)
}
(the actual routine should call helper(List(""), input))