I'd like to reverse a list of lists, recursively, in Scala.
I've written deep list reverses in Python like this:
def deepReverse(items):
if type(items) == list:
return [deepReverse(item) for item in reversed(items)]
else:
return items
How would I do the equivalent in Scala? The problem isn't the algorithm - it's the type stuff, which I'm newer on.
I need the function to take a list of [T], or a List[List[T]], or a list of T's and lists of Ts, to any arbitrary depth. I tried making a case class to do that based on an example I'd seen elsewhere. I don't want a function that just returns Any and accepts Any; that feels like cheating.
case class NL[+T](val v : Either[List[NL[T]],T])
Still, I couldn't quite get my types to balance out. I'm new to Scala, but I figured it'd be a perfect opportunity to mess with recursion and typing.
It's actually not too hard to write a version of the type class approach that sschaef proposes that will work for arbitrarily nested lists:
trait Reverser[C] {
def reverse(xs: C): C
}
implicit def rev[A](implicit ev: Reverser[A] = null) = new Reverser[List[A]] {
def reverse(xs: List[A]) =
Option(ev).map(r => xs map r.reverse).getOrElse(xs).reverse
}
def deepReverse[A](xs: A)(implicit ev: Reverser[A]): A = ev.reverse(xs)
The implicit argument ev in our rev method is evidence that A itself is reversable, and if ev is null that means it's not. If we have this evidence that A is reversable, we use it to reverse the elements of our List[A] (this is what the map is doing), and then we reverse the list itself. If we don't have this evidence (the getOrElse case), we can just reverse the list.
We could write rev a little less concisely (but possibly more performantly) like this:
implicit def rev[A](implicit ev: Reverser[A] = null) = if (ev == null) {
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
} else {
new Reverser[List[A]] {
def reverse(xs: List[A]) = (xs map ev.reverse).reverse
}
}
To test either of these two versions, we can write the following:
scala> deepReverse(List.tabulate(3)(identity))
res0: List[Int] = List(2, 1, 0)
scala> deepReverse(List.tabulate(2,3) { case (a, b) => a + b })
res1: List[List[Int]] = List(List(3, 2, 1), List(2, 1, 0))
scala> deepReverse(List.tabulate(2, 3, 4, 5, 6) {
| case (a, b, c, d, e) => a + b + c + d + e
| }).head.head.head.head
res2: List[Int] = List(15, 14, 13, 12, 11, 10)
As expected.
I should add that the following is a more common idiom for getting the implicits right in a case like this:
trait ReverserLow {
implicit def listReverser[A] = new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.reverse
}
}
object ReverserHigh extends ReverserLow {
implicit def nestedListReverser[A](implicit ev: Reverser[A]) =
new Reverser[List[A]] {
def reverse(xs: List[A]) = xs.map(ev.reverse).reverse
}
}
import ReverserHigh._
If we'd just written listReverser and nestedListReverser at the same level, we'd get the following error when we try to reverse a list of lists:
scala> deepReverse(List.tabulate(2, 3)(_ + _))
<console>:12: error: ambiguous implicit values:
both method listReverser...
and method nestedListReverser...
match expected type Reverser[List[List[Int]]]
deepReverse(List.tabulate(2, 3)(_ + _))
The standard approach to prioritizing the two is to put the lower priority implicit in a trait (WhateverLow) and the other in an object (WhateverHigh) that extends that trait. In a fairly simple case like this, though, it's more concise (and clearer, to my eye) to use the default argument trick in my rev method above. But you're more likely to see the other version in other people's code.
If you wanna have this really typesafe then the typeclass pattern is your friend:
object Reverse extends App {
trait Reverser[C] {
def reverse(xs: C): C
}
implicit def List1Reverser[A] = new Reverser[List[A]] {
def reverse(xs: List[A]) =
xs.reverse
}
implicit def List2Reverser[A] = new Reverser[List[List[A]]] {
def reverse(xs: List[List[A]]) =
xs.map(_.reverse).reverse
}
implicit def List3Reverser[A] = new Reverser[List[List[List[A]]]] {
def reverse(xs: List[List[List[A]]]) =
xs.map(_.map(_.reverse).reverse).reverse
}
def deepReverse[A](xs: A)(implicit rev: Reverser[A]): A =
rev.reverse(xs)
val xs = List(1,2)
val xxs = List(List(1,2),List(1,2),List(1,2))
val xxxs = List(List(List(1,2),List(1,2)),List(List(1,2),List(1,2)),List(List(1,2),List(1,2)))
println(deepReverse(xs))
println(deepReverse(xxs))
println(deepReverse(xxxs))
}
The only problem with this is that you need a typeclass for each nested list type.
Related
This question already has answers here:
Scala flatten a List
(5 answers)
Closed 4 months ago.
how to achieve below result list from the list val l1 = List(1,2,List(3,List(4,5,6),5,6,7)?
result = List(1,2,3,4,5,6,7)
Strangely enough, this actually works in Scala 3, and is kinda-sorta "type-safe":
type NestedList[A] = A match {
case Int => Int | List[NestedList[Int]]
case _ => A | List[NestedList[A]]
}
val input: NestedList[Int] = List(1,2,List(3,List(4,5,6),5,6,7))
def flattenNested[A](nested: NestedList[A]): List[A] =
nested match
case xs: List[NestedList[A]] => xs.flatMap(flattenNested)
case x: A => List(x)
val result: List[Int] = flattenNested(input)
println(result.distinct)
I'd consider this more of a curiosity, though, it feels quite buggy. See also discussion here. As it is now, it would be much preferable to model the input data properly as an enum, so one doesn't end up with a mix of Ints and Lists in the first place.
The following would work,
def flattenOps(l1: List[Any]): List[Int] = l1 match {
case head :: tail => head match {
case ls: List[_] => flattenOps(ls) ::: flattenOps(tail)
case i: Int => i :: flattenOps(tail)
}
case Nil => Nil
}
flattenOps(l1).distinct
Regardless the strange input, I would like to make a common pattern of my items in the list:
import scala.reflec.ClassTag
sealed trait ListItem[A] {
def flattenedItems: List[A]
}
case class SingleItem[A](value: A) extends ListItem[A] {
def flattenedItems: List[A] = value :: Nil
}
case class NestedItems[A](values: List[ListItem[A]]) extends ListItem[A] {
def flattenedItems: List[A] = values.flatMap(_.flattenedItems)
}
// The above would probably take much less lines of code in Scala 3
object ListItem {
def parse[A : ClassTag](value: Any): ListItem[A] = {
value match {
case single: A => SingleItem(single)
case nested: List[Any] => NestedItems(nested.map(parse[A]))
}
}
}
Then given the list as:
val l = List(1, 2, List(3, List(4, 5, 6), 5, 6, 7))
You can parse each value, and then get flattened values using the ListItem's method:
val itemizedList: List[ListItem[Int]] = l.map(ListItem.parse[Int])
val result = itemizedList.flatMap(_.flattenedItems).distinct
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.
I'm trying to write the get method for a key, value pair implemented using a list. I want to use the Option type as I heard its good for this but I'm new to Scala and I'm not really sure how to use it in this case...
This is as far as I got, only the method header.
def get(key : String): Option[Any] = {}
My guess is you are looking for something like this:
class KeyValueStore(pairs: List[(String, Any)]) {
def get(key: String): Option[Any] = pairs.collectFirst {
case (k, v) if k == key => v
}
}
This uses the collectFirst method for sequences. If you want a more "do it yourself" approach, this should work:
def get(key: String): Option[Any] = {
def search(xs: List[(String, Any)]): Option[Any] = {
xs match {
case List() => None //end of list and key not found. We return None
case (k, v) :: rest if k == key => Some(v) // found our key. Returning some value
case _ :: rest => search(rest) // not found until nou. Carrying on with the rest of the list
}
search(pairs)
}
}
You can turn a List of Pairs into a Map:
class Store[K, V](values: List[(K, V)]) {
val map = values.toMap
def get(key: K): Option[V] = map get key
}
Although #Marius' collectFirst version is probably the most elegant (and maybe a little bit faster as it only uses one closure), I find it more intuitive to use find for your problem :
def get[A, B](key: A, pairs: List[(A, B)]): Option[B] = pairs.find(_._1 == key).map(_._2)
In case you were wondering (or need high performance), you will need either #Marius' recursive or the following imperative version which may look more familiar (although less idiomatic):
def get[A, B](key: A, pairs: List[(A, B)]): Option[B] = {
var l = pairs
var found: Option[B] = None
while (l.nonEmpty && found.isEmpty) {
val (k, v) = l.head
if (k == key) {
found = Some(v)
} else {
l = l.tail
}
}
found
}
What you must understand is that Option[B] is a class that may either be instantiated to None (which replaces and improves the null reference used in other languages) or Some(value: B). Some is a case class, which allows, among other neat features, to instantiate it without the new keyword (thanks to some compiler magic, Google Scala case class for more info). You can think of Option as a List which may contain either 0 or 1 element: most operations that can be done on sequences can also be applied to Options (such as map in the find version).
I have often the need to check if many values are equal and in case extract the common value. That is, I need a function that will work like follows:
extract(List()) // None
extract(List(1,2,3)) // None
extract(List(2,2,2)) // Some(2)
Assuming one has a pimp that will add tailOption to seqs (it is trivial to write one or there is one in scalaz), one implementation looks like
def extract[A](l: Seq[A]): Option[A] = {
def combine(s: A)(r: Seq[A]): Option[A] =
r.foldLeft(Some(s): Option[A]) { (acc, n) => acc flatMap { v =>
if (v == n) Some(v) else None
} }
for {
h <- l.headOption
t <- l.tailOption
res <- combine(h)(t)
} yield res
}
Is there something like that - possibly more general - already in Scalaz, or some simpler way to write it?
This seems like a really complicated way to write
def extract[A](l:Seq[A]):Option[A] = l.headOption.flatMap(h =>
if (l.tail.forall(h==)) Some(h) else None)
You don't need tailOption, since the anonymous function that gets passed as an argument to flatMap is only executed if l is not empty.
If you only want to delete duplicates toSet is enough:
def equalValue[A](xs: Seq[A]): Option[A] = {
val set = xs.toSet
if (set.size == 1) Some(set.head) else None
}
scala> equalValue(List())
res8: Option[Nothing] = None
scala> equalValue(List(1,2,3))
res9: Option[Int] = None
scala> equalValue(List(2,2,2))
res10: Option[Int] = Some(2)
This is a fluent solution
yourSeq.groupBy(x => x) match {case m if m.size==1 => m.head._1; case _ => None}
You could use a map to count the number of occurrences of each element in the list and then return only those that occur more than once:
def extract[T](ts: Iterable[T]): Iterable[T] = {
var counter: Map[T, Int] = Map()
ts.foreach{t =>
val cnt = counter.get(t).getOrElse(0) + 1
counter = counter.updated(t, cnt)
}
counter.filter(_._2 > 1).map(_._1)
}
println(extract(List())) // List()
println(extract(List(1,2,3))) // List()
println(extract(List(2,2,2))) // List(2)
println(extract(List(2,3,2,0,2,3))) // List(2,3)
You can also use a foldLeft instead of foreach and use the empty map as the initial accumulator of foldLeft.
Im attempting to create a new operator :? on lists, which operates the same as :: except if the value if null, then the original list is returned. I have written the following, however it soon dawned that I didn't really know what I was doing....
object ImplicitList {
implicit def extendIterator[T](i : List[T]) = new ListExtension(i)
}
class ListExtension[T <: Any](i : List[T]) {
def :?[B >: T] (x: B): List[B] = if (x != null) x :: i else i
}
final case class :?[B](private val hd: B, private val tl: ListExtension[B]) extends ListExtension[B](tl.:?(hd))
What you want is the enhance-my-library pattern. With this you can add a new method to List. Here's how that would look:
class EnhancedList[T](self: List[T]) {
def ?:(t: T) =
t match {
case null => self
case _ => t :: self
}
}
implicit def enhanceList[T](self: List[T]) = new EnhancedList(self)
So there's a class EnhancedList that wraps List where the new method ?: is defined, and an implicit function that converts List to EnhancedList when ?: is called. Note that you have to use ?: instead of :? because Scala's rules are such that an operator is right-associative if and only if it ends in a :.
Here's how it gets used:
scala> val l = List("a","b","c")
l: List[java.lang.String] = List(a, b, c)
scala> null ?: l
res136: List[java.lang.String] = List(a, b, c)
scala> "d" ?: l
res137: List[java.lang.String] = List(d, a, b, c)