How to substitute ::: in scala - list

I have written a flatten function from scratch that takes a nested list as input and outputs another.
def flatten[A] (list:List[List[A]]):List[A]
I used scala's ':::' to bind the two lists and it worked fine. However, my exercise prohibits me from using that or any built in method ( exercise from a personal scala book).
Now, i have written a helper method that merges those two list called merge.
How would merge fit in a new version of the function flatten?

If you have method merge you could use foldLeft for flattening the list of lists:
list.foldLeft(List[A]())(merge)

def merge1[T](l1: List[T], l2: List[T]): List[T] =
l1.reverse.foldLeft(l2)((acc, e) => e :: acc)
/** for large lists will throws Stackoverflow */
def merge2[T](l1: List[T], l2: List[T]): List[T] =
l1.foldRight(l2)((e, acc) => e :: acc)
def flatten[A](list: List[List[A]]): List[A] =
list.foldLeft(Nil: List[A])(merge1)
If you want to add your merge method to List type, you can write:
implicit class ListExt[T](l: List[T]) {
def merge(l2: List[T]): List[T] = merge1(l, l2)
}
def flatten2[A](list: List[List[A]]): List[A] =
list.foldLeft(Nil: List[A])((acc, e) => acc merge e)

Related

Optimize solution for the given coding problem

I am a newbie in Scala and I am trying to resolve the following simple coding problem:
Write a listOfLists recursive method that takes a number of strings as varargs and then
creates a list of lists of strings, with one less string in each, so for example:
listOfLists("3","2","1") should give back: List(List("3","2","1"), List("2","1"), List("1"))
The solution I've found is the following:
def listOfLists(strings: String*): List[List[String]] = {
val strLength = strings.length
#tailrec
def recListOfList(result: List[List[String]], accumulator: Int): List[List[String]] = {
accumulator match {
case x if x < strLength =>
recListOfList(result :+ (strings.toList.takeRight(strings.length - accumulator)), accumulator + 1 )
case _ => result
}
}
val res: List[List[String]] = List(strings.toList)
recListOfList(res, 1)
}
The solution works, however I think it could be written much more better.
A problem I can see is that I convert the varargs to a List with the toList method, but a hint that the problem gave me is to use the eta expansion _* but I don't know how to use it in this context.
Then, I tried to find another way to write in a more efficient way the following instruction:
strings.toList.takeRight(strings.length - accumulator))
but this is the only solution that came up in my mind.
Any review is welcome (also say that this solution is a total mess :D (providing the right reasons))
This meets all the specified requirements.
def listOfLists(strings: String*): List[List[String]] =
if (strings.isEmpty) Nil
else strings.toList :: listOfLists(strings.tail:_*)
You can do this:
def listOfLists(strings: String*): List[List[String]] = {
#annotation.tailrec
def loop(remaining: List[String], acc: List[List[String]]): List[List[String]] =
remaining match {
case head :: tail =>
loop(remaining = tail, (head :: tail) :: acc)
case Nil =>
acc.reverse
}
loop(remaining = strings.toList, acc = List.empty)
}
I believe the code is self-explanatory; but, feel free to ask any questions you may have.
You can see the code running here.
Not a recursive method but worth noting that tails in the standard library can do most of this. Then map and filter to convert to correct type and filter out empty list.
def listOfLists(strings: String *): List[List[String]] = strings.tails.map(_.toList).filter(_.nonEmpty).toList
Test:
scala> listOfLists("a","b","c")
val res6: List[List[String]] = List(List(a, b, c), List(b, c), List(c))
Using almost the same idea you can rewrite your solution in cleaner way:
def listOfLists(strings: String*): List[List[String]] = {
#tailrec
def recListOfList(curr: List[String], accumulator: Seq[List[String]]): Seq[List[String]] = {
curr match {
case head :: tail => recListOfList(tail, curr +: accumulator)
case _ => accumulator
}
}
recListOfList(strings.toList, Nil)
.reverse
.toList
}
With the splat(_*) operator, which adapts a sequence (Array, List, Seq, Vector, etc.) to varargs parameter you can create a shorter solution, but it will not be tail-recursive:
def listOfLists(strings: String*): List[List[String]] = {
val curr = strings.toList
curr match {
case Nil => Nil
case x :: tail => curr :: listOfLists(tail:_*)
}
}
From Scala 2.13 you can use List.unfold and Option.when:
def listOfLists(strings: String*): List[List[String]] = {
List.unfold(strings) { s =>
Option.when(s.nonEmpty)(s.toList, s.tail)
}
}
Code run at Scastie.

Discussing implementation of list flattener function in scala

The flatten function is a function which take a list of list and return a list which is the concatenation of all the lists. As an exercise for functional programming in scala, we have to implement that function with a linear complexity. My solution is :
def flatten[A](l: List[List[A]]): List[A] = {
def outer(ll: List[List[A]]):List[A] = {
ll match {
case Nil => Nil
case Cons(h,t) => inner(t, h)
}
}
def inner(atEnd: List[List[A]], ll: List[A]): List[A] = {
ll match {
case Nil => outer(atEnd)
case Cons(h,t) => Cons(h, inner(atEnd, t))
}
}
outer(l)
}
It works. Now I looked at the solution proposed :
def append[A](a1: List[A], a2: List[A]): List[A] =
a1 match {
case Nil => a2
case Cons(h,t) => Cons(h, append(t, a2))
}
def flatten2[A](l: List[List[A]]): List[A] =
foldRight(l, Nil:List[A])(append)
I am suspicious that flatten2 is really linear. At each iteration of foldLeft, the function append is called. This function will parse all the nodes of the accumulator. The first time, the accumulator is Nil, the second it is l.get(1) then l.get(1) + l.get(2)... So the first list in l won't be crossed only once, but l.length - 1 until the end of the function. Am I right ?
While my implementation really cross each list only once. Is my implementation really faster ?
Consider for example flatten2 (List(List(1,2,3), List(4,5), List(6))), which expands to:
append(List(1,2,3),
append(List(4,5),
append(List(6),
Nil)))
As a comment in the link says, "append takes time proportional to its first argument" and therefore "this function is linear in the total length of all lists". (On the other hand, neither flatten2 nor flatten is tail-recursive, though.)

Filter usage in shapeless, Scala

It is easy to filter HList in shapeless by type:
val hlist = 1 :: 2 :: "3" :: true :: false :: HNil
hlist.filter[Int]
But how can I make my custom type filter? I want smth like that: for example I got list of some functions:
def function1(s: String) = s.toInt
def function2(s: String) = s.toDouble
def function3(i: Int) = i.toDouble
val hflist = function1 _ :: function3 _ :: function2 _ :: HNil
hflist customFilter[String] //> function1 _ :: function2 _ :: HNil
So after usage of this filter, list of functions from type String to some other type will be constructed.
I had an idea to use map for this, but it was not successfull.
EDITION
More information about my comment:
I tried to test this ideas in map:
So if i got some lists (lets operate with hlist & hflist):
object allFunction extends Poly1 {
implicit def default[T, M] =
at[T => M](t => {
object grabStringFunc extends skip {
implicit def stringFunc[A] = at[T => A](_ :: HNil)
}
println(hflist flatMap grabStringFunc) //> here we should see result, list of functions
})
hlist map allFunction
//> result of this should be smth like (types)
//> shapeless.::[Int => Double,shapeless.HNil]]
//> shapeless.::[Int => Double,shapeless.HNil]]
//> shapeless.::[String => Int,shapeless.::[String => Double,shapeless.HNil]]
//> shapeless.HNil
//> shapeless.HNil
Very interesting, why it compiles and works incorrect? As I think it is not works, cause object cant take type prameters in such a way...
The easiest way is to use a fold. First we need a polymorphic function that will add each item to the accumulator if it has the desired type (String => A for some A), and ignore it otherwise:
trait ignore extends Poly2 {
implicit def default[A, L <: HList] = at[A, L]((_, l) => l)
}
object keepStringFunc extends ignore {
implicit def stringFunc[A, L <: HList] = at[String => A, L](_ :: _)
}
Now the following will give the result you want in both 1.2.4 and 2.0.0-M1:
val filtered = hflist.foldRight(HNil)(keepStringFunc)
You could also write your own type class on the model of Filter, FilterAux (or Filter.Aux), etc.—and doing so would be a good exercise if you're trying to get the hang of Shapeless—but foldRight is a lot simpler.
Update: actually, for what it's worth, there's a slightly more concise way to do this with flatMap:
trait skip extends Poly1 {
implicit def default[A] = at[A](_ => HNil)
}
object grabStringFunc extends skip {
implicit def stringFunc[A] = at[String => A](_ :: HNil)
}
val filtered = hflist flatMap grabStringFunc
I personally find the foldRight version a little more obvious, but this one's also pretty elegant.
In response to your comment: you can make the solution a little more generic like this:
trait skip extends Poly1 {
implicit def default[A] = at[A](_ => HNil)
}
trait grabFuncFrom[T] extends skip {
implicit def stringFunc[A] = at[T => A](_ :: HNil)
}
object grabStringFunc extends grabFuncFrom[String]
val filtered = hflist flatMap grabStringFunc
But you're still going to need that last step where you create the higher rank function as an object (see e.g. this answer and Miles's comment there for some discussion of this issue).

Scala for loop Replace on List

Maybe this might be easy to fix but can you help me out or guide me to a solution. I have a remove function that goes through a List of tuples "List[(String,Any)]" and im trying to replace the 1 index of the value with Nil when the list is being looped over.
But when I try to replace the current v with Nil, it say the v is assigned to "val". Now I understand that scala lists are immutable. So maybe this is what is going wrong?
I tried a Tail recursion implementation as will but when I get out of the def there is a type mismatch. ie: is unit but required: Option[Any]
// remove(k) removes one value v associated with key k
// from the dictionary, if any, and returns it as Some(v).
// It returns None if k is associated to no value.
def remove(key:String):Option[Any] = {
for((k,v) <- d){
if(k == key){
var temp:Option[Any] = Some(v)
v = Nil
return temp
}
}; None
}
Here was the other way of trying to figure out
def remove(key:String):Option[Any] = {
def removeHelper(l:List[(String,Any)]):List[(String,Any)] =
l match {
case Nil => Nil
case (k,v)::t => if (key == k) t else (k,v)::removeHelper(t)
}
d = removeHelper(d)
}
Any Suggestions? This is a homework/Project for school thought I might add that for the people that don't like to help with homework.
Well, there are many ways of answering that question. I'll be outlining the ones I can think of here with my own implementations, but the list is by no means exhaustive (nor, probably, the implementations optimal).
First, you can try with existing combinators - the usual suspects are map, flatMap, foldLeft and foldRight:
def remove_flatMap(key: String, list: List[(String, Any)]): List[(String, Any)] =
// The Java developer in me rebels against creating that many "useless" instances.
list.flatMap {a => if(a._1 == key) Nil else List(a)}
def remove_foldLeft(key: String, list: List[(String, Any)]): List[(String, Any)] =
list.foldLeft(List[(String, Any)]()) {(acc, a) =>
if(a._1 == key) acc
else a :: acc
// Note the call to reverse here.
}.reverse
// This is more obviously correct than the foldLeft version, but is not tail-recursive.
def remove_foldRight(key: String, list: List[(String, Any)]): List[(String, Any)] =
list.foldRight(List[(String, Any)]()) {(a, acc) =>
if(a._1 == key) acc
else a :: acc
}
The problem with these is that, as far as I'm aware, you cannot stop them once a certain condition has been reached: I don't think they solve your problem directly, since they remove all instances of key rather than the first.
You also want to note that:
foldLeft must reverse the list once it's done, since it appends elements in the "wrong" order.
foldRight doesn't have that flaw, but is not tail recursive: it will cause memory issues on large lists.
map cannot be used for your problem, since it only lets us modify a list's values but not its structure.
You can also use your own implementation. I've included two versions, one that is tail-recursive and one that is not. The tail-recursive one is obviously the better one, but is also more verbose (I blame the ugliness of using a List[(String, Any)] rather than Map[String, Any]:
def remove_nonTailRec(key: String, list: List[(String, Any)]): List[(String, Any)] = list match {
case h :: t if h._1 == key => t
// This line is the reason our function is not tail-recursive.
case h :: t => h :: remove_nonTailRec(key, t)
case Nil => Nil
}
def remove_tailRec(key: String, list: List[(String, Any)]): List[(String, Any)] = {
#scala.annotation.tailrec
def run(list: List[(String, Any)], acc: List[(String, Any)]): List[(String, Any)] = list match {
// We've been aggregating in the "wrong" order again...
case h :: t if h._1 == key => acc.reverse ::: t
case h :: t => run(t, h :: acc)
case Nil => acc.reverse
}
run(list, Nil)
}
The better solution is of course to use the right tool for the job: a Map[String, Any].
Note that I do not think I answer your question fully: my examples remove key, while you want to set it to Nil. Since this is your homework, I'll let you figure out how to change my code to match your requirements.
List is the wrong collection to use if any key should only exist once. You should be using Map[String,Any]. With a list,
You have to do extra work to prevent duplicate entries.
Retrieval of a key will be slower, the further down the list it appears. Attempting to retrieve a non-existent key will be slow in proportion to the size of the list.
I guess point 2 is maybe why you are trying to replace it with Nil rather than just removing the key from the list. Nil is not the right thing to use here, really. You are going to get different things back if you try and retrieve a non-existent key compared to one that has been removed. Is that really what you want? How much sense does it make to return Some(Nil), ever?
Here's a couple of approaches which work with mutable or immutable lists, but which don't assume that you successfully stopped duplicates creeping in...
val l1: List[(String, Any)] = List(("apple", 1), ("pear", "violin"), ("banana", Unit))
val l2: List[(Int, Any)] = List((3, 1), (4, "violin"), (7, Unit))
def remove[A,B](key: A, xs: List[(A,B)]) = (
xs collect { case x if x._1 == key => x._2 },
xs map { case x if x._1 != key => x; case _ => (key, Nil) }
)
scala> remove("apple", l1)
res0: (List[(String, Any)], List[(String, Any)]) = (List((1)),List((apple, List()),(pear,violin), (banana,object scala.Unit)))
scala> remove(4, l2)
res1: (List[(Int, Any)], List[(Int, Any)]) = (List((violin)),List((3,1), (4, List()), (7,object scala.Unit)))
scala> remove("snark", l1)
res2: (List[Any], List[(String, Any)]) = (List(),List((apple,1), (pear,violin), (banana,object scala.Unit)))
That returns a list of matching values (so an empty list rather than None if no match) and the remaining list, in a tuple. If you want a version that just completely removes the unwanted key, do this...
def remove[A,B](key: A, xs: List[(A,B)]) = (
xs collect { case x if x._1 == key => x._2 },
xs filter { _._1 != key }
)
But also look at this:
scala> l1 groupBy {
case (k, _) if k == "apple" => "removed",
case _ => "kept"
}
res3: scala.collection.immutable.Map[String,List[(String, Any)]] = Map(removed -> List((apple,1)), kept -> List((pear,violin), (banana,object scala.Unit)))
That is something you could develop a bit. All you need to do is add ("apple", Nil) to the "kept" list and extract the value(s) from the "removed" list.
Note that I am using the List combinator functions rather than writing my own recursive code; this usually makes for clearer code and is often as fast or faster than a hand-rolled recursive function.
Note also that I don't change the original list. This means my function works with both mutable and immutable lists. If you have a mutable list, feel free to assign my returned list as the new value for your mutable var. Win, win.
But please use a map for this. Look how simple things become:
val m1: Map[String, Any] = Map(("apple", 1), ("pear", "violin"), ("banana", Unit))
val m2: Map[Int, Any] = Map((3, 1), (4, "violin"), (7, Unit))
def remove[A,B](key: A, m: Map[A,B]) = (m.get(key), m - key)
scala> remove("apple", m1)
res0: (Option[Any], scala.collection.immutable.Map[String,Any]) = (Some(1),Map(pear -> violin, banana -> object scala.Unit))
scala> remove(4, m2)
res1: (Option[Any], scala.collection.immutable.Map[Int,Any]) = (Some(violin),Map(3 -> 1, 7 -> object scala.Unit))
scala> remove("snark", m1)
res2: res26: (Option[Any], scala.collection.immutable.Map[String,Any]) = (None,Map(apple -> 1, pear -> violin, banana -> object scala.Unit))
The combinator functions make things easier, but when you use the right collection, it becomes so easy that it is hardly worth writing a special function. Unless, of course, you are trying to hide the data structure - in which case you should really be hiding it inside an object.

How to replace(fill) None entries on List of Options from another List using idiomatic Scala?

I have a List[Option[MyClass]] with None in random positions and I need to 'fill' that list again, from a List[MyClass], maintaining the order.
Here are sample lists and expected result:
val listA = List(Some(3),None,Some(5),None,None)
val listB = List(7,8,9)
val expectedList = List(Some(3), Some(7), Some(5), Some(8), Some(9))
So, how would be a idiomatic Scala to process that list?
def fillL[T](a:List[Option[T]], b:List[T]) = {
val iterB = b.iterator
a.map(_.orElse(Some(iterB.next)))
}
The iterator solution is arguably idiomatic Scala, and is definitely concise and easy to understand, but it's not functional—any time you call next on an iterator you're firmly in the land of side effects.
A more functional approach would be to use a fold:
def fillGaps[A](gappy: List[Option[A]], filler: List[A]) =
gappy.foldLeft((List.empty[Option[A]], filler)) {
case ((current, fs), Some(item)) => (current :+ Some(item), fs)
case ((current, f :: fs), None) => (current :+ Some(f), fs)
case ((current, Nil), None) => (current :+ None, Nil)
}._1
Here we move through the gappy list while maintaining two other lists: one for the items we've processed, and the other for the remaining filler elements.
This kind of solution isn't necessarily better than the other—Scala is designed to allow you to mix functional and imperative constructions in that way—but it does have potential advantages.
I'd just write it in the straightforward way, matching on the heads of the lists and handling each case appropriately:
def fill[A](l1: List[Option[A]], l2: List[A]) = (l1, l2) match {
case (Nil, _) => Nil
case (_, Nil) => l1
case (Some(x) :: xs, _) => Some(x) :: fill(xs, l2)
case (None :: xs, y :: ys) => Some(y) :: fill(xs, ys)
}
Presumably once you run out of things to fill it with, you just leave the rest of the Nones in there.