scala case class from sequence - scala

case class Foo(a: Int, b: Int, c: Int)
val s = Seq(1, 2, 3)
val t = (1, 2, 3)
I know I can create case class from tuple:
Foo.tupled(t)
but how can I create case class from Sequence? I have ~10 integer elements in the sequence.

One option is to add corresponding apply factory method to companion object something like so
object Foo {
def apply(xs: Seq[Int]): Option[Foo] = {
xs match {
case Seq(a, b, c) => Some(Foo(a, b, c))
case _ => None
}
}
}
Foo(s) // : Option[Foo] = Some(value = Foo(a = 1, b = 2, c = 3))

How aboud this?
case class Foo(xs: Int*)
val a = Foo(1,2,3)
val b = Foo(1,2,3,4,5)
val c = Foo((1 to 10).toList: _*)
println(a.xs) // Seq[Int](1,2,3)
println(c.xs) // Seq[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Related

Scala: Why the Int type list contains String as well?

val wordList = List("I", "want", "to", "learn", "scala")
val wordSizeList = list.map(x=>x.length)
def func[A, B](a:List[A]):List[B]={
a.collect({case x:B => x})
}
val result = func[Any, Int](wordList ::: wordSizeList)
Below is the worksheet result
wordList: List[String] = List(I, want, to, learn, scala)
wordSizeList: List[Int] = List(1, 4, 2, 5, 5)
func: [A, B](a: List[A])List[B]
result: List[Int] = List(I, want, to, learn, scala, 1, 4, 2, 5, 5)
why doesn't it filter based on the Generic type "B"?
And if you see the result list, how can a Int type list can contain String as well?
Looks to me a type erasure problem, which can be remedied with a ClassTag:
import scala.reflect.ClassTag
def func[A, B : ClassTag](a: List[A]): List[B] = {
a.collect{ case x: B => x }
}
val result = func[Any, Int](wordList ::: wordSizeList)
// result: List[Int] = List(1, 4, 2, 5, 5)

How to assert 2 scala objects containing list in Scala test?

I have a case class like this.
case class A(a: Int, List[Int])
Now I want to assert two instances of A
val a = A(100, List(2, 4))
val b = A(100, List(4, 2))
a shouldBe b
a shouldEqual b
Above two statements fail because List(2, 4) does not have same order as List(4, 2).
Is there a way to assert whole objects of A i.e. a and b, so that it passes ?
Using the Inside mixing you can do something like:
class Spec extends FlatSpec with Matchers with Inside {
it should "be equal regarding order" in {
val result = A(100, List(2, 4))
inside(result) {
case A(a, list) =>
a shouldBe 100
list should contain theSameElementsAs List(4, 2)
}
}
}
Consider defining custom equality like so
case class A(a: Int, l: List[Int])
object A {
implicit val aEq: Equality[A] = (a: A, b: Any) => b match {
case bb: A => bb.a == a.a && bb.l.sorted == a.l.sorted
case _ => false
}
}
class ExampleSpec extends FlatSpec with Matchers {
"As" should "be equal ignoring the order of elements in lists" in {
val aa = A(100, List(2, 4))
val bb = A(100, List(4, 2))
aa should equal (bb)
}
}
or matchPattern like so
"As" should "be equal ignoring the order of elements in lists" in {
case class A(a: Int, l: List[Int])
val aa = A(100, List(2, 4))
val bb = A(100, List(4, 3))
aa should matchPattern { case A(a, l) if bb.a == a && bb.l.sorted == l.sorted => }
}

List of every n-th item in a given list

This is a simple exercise I am solving in Scala: given a list l return a new list, which contains every n-th element of l. If n > l.size return an empty list.
def skip(l: List[Int], n: Int) =
Range(1, l.size/n + 1).map(i => l.take(i * n).last).toList
My solution (see above) seem to work but I am looking for smth. simpler. How would you simplify it?
Somewhat simpler:
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// n == 3
scala> l.drop(2).grouped(3).map(_.head).toList
res0: List[Int] = List(3, 6, 9)
// n > l.length
scala> l.drop(11).grouped(12).map(_.head).toList
res1: List[Int] = List()
(the toList just to force the iteratot to be evaluated)
Works with infinite lists:
Stream.from(1).drop(2).grouped(3).map(_.head).take(4).toList
res2: List[Int] = List(3, 6, 9, 12)
scala> def skip[A](l:List[A], n:Int) =
l.zipWithIndex.collect {case (e,i) if ((i+1) % n) == 0 => e} // (i+1) because zipWithIndex is 0-based
skip: [A](l: List[A], n: Int)List[A]
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> skip(l,3)
res2: List[Int] = List(3, 6, 9)
scala> skip(l,11)
res3: List[Int] = List()
A bit more readable and the loop size is O(l.length/n):
def skip(l: List[Int], n: Int) = {
require(n > 0)
for (step <- Range(start = n - 1, end = l.length, step = n))
yield l(step)
}
Fold left approach O(n)
def skip(xs: List[Int], n: Int) = {
xs.foldLeft((List[Int](), n)){ case ((acc, counter), x) =>
if(counter==1)
(x+:acc,n)
else
(acc, counter-1)
}
._1
.reverse
}
scala > skip(List(1,2,3,4,5,6,7,8,9,10), 3)
Tailrec less readable approach O(n)
import scala.annotation.tailrec
def skipTR(xs: List[Int], n: Int) = {
#tailrec
def go(ys: List[Int], acc: List[Int], counter: Int): List[Int] = ys match {
case k::ks=>
if(counter==1)
go(ks, k+:acc , n)
else
go(ks, acc, counter-1)
case Nil => acc
}
go(xs, List(), n).reverse
}
skipTR(List(1,2,3,4,5,6,7,8,9,10), 3)
You could omit toList if you don't mind an iterator:
scala> def skip[A](l:List[A], n:Int) =
l.grouped(n).filter(_.length==n).map(_.last).toList
skip: [A](l: List[A], n: Int)List[A]
scala> skip (l,3)
res6: List[Int] = List(3, 6, 9)
Two approaches based in filter on indexes, as follows,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthA(n: Int) = n match {
case 0 => List()
case _ => (1 to a.size).filter( _ % n == 0).map { i => list(i-1)}
}
def nthB(n: Int) = n match {
case 0 => List()
case _ => list.zip(Stream.from(1)).filter(_._2 % n == 0).unzip._1
}
}
and so for a given list
val a = ('a' to 'z').toList
we have that
a.nthA(5)
res: List(e, j, o, t, y)
a.nthA(123)
res: List()
a.nthA(0)
res: List()
Update
Using List.tabulate as follows,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthC(n: Int) = n match {
case 0 => List()
case n => List.tabulate(list.size) {i =>
if ((i+1) % n == 0) Some(list(i))
else None }.flatten
}
}

Scala, extending the iterator

Im looking to extended the iterator to create a new method takeWhileInclusive, which will operate like takeWhile but include the last element.
My issue is what is best practice to extend the iterator to return a new iterator which I would like to be lazy evaluated. Coming from a C# background I normal use IEnumerable and use the yield keyword, but such an option doesn't appear to exist in Scala.
for example I could have
List(0,1,2,3,4,5,6,7).iterator.map(complex time consuming algorithm).takeWhileInclusive(_ < 6)
so in this case the takeWhileInclusive would only have resolve the predicate on the values until I get the a result greater than 6, and it will include this first result
so far I have:
object ImplicitIterator {
implicit def extendIterator(i : Iterator[Any]) = new IteratorExtension(i)
}
class IteratorExtension[T <: Any](i : Iterator[T]) {
def takeWhileInclusive(predicate:(T) => Boolean) = ?
}
You can use the span method of Iterator to do this pretty cleanly:
class IteratorExtension[A](i : Iterator[A]) {
def takeWhileInclusive(p: A => Boolean) = {
val (a, b) = i.span(p)
a ++ (if (b.hasNext) Some(b.next) else None)
}
}
object ImplicitIterator {
implicit def extendIterator[A](i : Iterator[A]) = new IteratorExtension(i)
}
import ImplicitIterator._
Now (0 until 10).toIterator.takeWhileInclusive(_ < 4).toList gives List(0, 1, 2, 3, 4), for example.
This is one case where I find the mutable solution superior:
class InclusiveIterator[A](ia: Iterator[A]) {
def takeWhileInclusive(p: A => Boolean) = {
var done = false
val p2 = (a: A) => !done && { if (!p(a)) done=true; true }
ia.takeWhile(p2)
}
}
implicit def iterator_can_include[A](ia: Iterator[A]) = new InclusiveIterator(ia)
The following requires scalaz to get fold on a tuple (A, B)
scala> implicit def Iterator_Is_TWI[A](itr: Iterator[A]) = new {
| def takeWhileIncl(p: A => Boolean)
| = itr span p fold (_ ++ _.toStream.headOption)
| }
Iterator_Is_TWI: [A](itr: Iterator[A])java.lang.Object{def takeWhileIncl(p: A => Boolean): Iterator[A]}
Here it is at work:
scala> List(1, 2, 3, 4, 5).iterator takeWhileIncl (_ < 4)
res0: Iterator[Int] = non-empty iterator
scala> res0.toList
res1: List[Int] = List(1, 2, 3, 4)
You can roll your own fold over a pair like this:
scala> implicit def Pair_Is_Foldable[A, B](pair: (A, B)) = new {
| def fold[C](f: (A, B) => C): C = f.tupled(pair)
| }
Pair_Is_Foldable: [A, B](pair: (A, B))java.lang.Object{def fold[C](f: (A, B) => C): C}
class IteratorExtension[T](i : Iterator[T]) {
def takeWhileInclusive(predicate:(T) => Boolean) = new Iterator[T] {
val it = i
var isLastRead = false
def hasNext = it.hasNext && !isLastRead
def next = {
val res = it.next
isLastRead = !predicate(res)
res
}
}
}
And there's an error in your implicit. Here it is fixed:
object ImplicitIterator {
implicit def extendIterator[T](i : Iterator[T]) = new IteratorExtension(i)
}
scala> List(0,1,2,3,4,5,6,7).toStream.filter (_ < 6).take(2)
res8: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> res8.toList
res9: List[Int] = List(0, 1)
After your update:
scala> def timeConsumeDummy (n: Int): Int = {
| println ("Time flies like an arrow ...")
| n }
timeConsumeDummy: (n: Int)Int
scala> List(0,1,2,3,4,5,6,7).toStream.filter (x => timeConsumeDummy (x) < 6)
Time flies like an arrow ...
res14: scala.collection.immutable.Stream[Int] = Stream(0, ?)
scala> res14.take (4).toList
Time flies like an arrow ...
Time flies like an arrow ...
Time flies like an arrow ...
res15: List[Int] = List(0, 1, 2, 3)
timeConsumeDummy is called 4 times. Am I missing something?

Instantiating a case class from a list of parameters

Given:
case class Foo(a: Int, b: String, c: Double)
you can say:
val params = Foo(1, "bar", 3.14).productIterator.toList
and get:
params: List[Any] = List(1, bar, 3.14)
Is there a way to "go backwards" and recreate a Foo object directly from this list, i.e.:
Foo.createFromList(params) // hypothetical
instead of writing:
Foo(params(0).asInstanceOf[Int], params(1).asInstanceOf[String], params(2).asInstanceOf[Double])
EDIT: it seems that it boils down to being able to send the elements of a list as parameters to a function without writing them out explicitly, e.g.:
def bar(a: Int, b: Int, c: Int) = //...
val list = List(1, 2, 3, 4, 5)
bar(list.take(3)) // hypothetical, instead of:
bar(list(0), list(1), list(2))
I would sort of expect to be able to do:
bar(list.take(3): _*)
but that doesn't seem to work.
EDIT: Solution based on extempore's answer, but invoking the constructor directly instead of using the apply method:
case class Foo(a: Int = 0, b: String = "bar", c: Double = 3.14) {
val cs = this.getClass.getConstructors
def createFromList(params: List[Any]) =
cs(0).newInstance(params map { _.asInstanceOf[AnyRef] } : _*).asInstanceOf[Foo]
}
Now you can do:
scala> Foo().createFromList(List(4, "foo", 9.81))
res13: Foo = Foo(4,foo,9.81)
You can also refactor the creation method into a trait:
trait Creatable[T <: Creatable[T]] {
val cs = this.getClass.getConstructors
def createFromList(params: List[Any]) =
cs(0).newInstance(params map { _.asInstanceOf[AnyRef] } : _*).asInstanceOf[T]
}
case class Bar(a: Int = 0, b: String = "bar", c: Double = 3.14) extends Creatable[Bar]
And do e.g.:
scala> val bar = Bar()
bar: Bar = Bar(0,bar,3.14)
scala> bar == bar.createFromList(bar.productIterator.toList)
res11: Boolean = true
scala> case class Foo(a: Int, b: String, c: Double)
defined class Foo
scala> val params = Foo(1, "bar", 3.14).productIterator.toList
params: List[Any] = List(1, bar, 3.14)
scala> Foo.getClass.getMethods.find(x => x.getName == "apply" && x.isBridge).get.invoke(Foo, params map (_.asInstanceOf[AnyRef]): _*).asInstanceOf[Foo]
res0: Foo = Foo(1,bar,3.14)
scala> Foo(1, "bar", 3.14) == res0
res1: Boolean = true
Edit: by the way, the syntax so far only being danced around for supplying the tuple as an argument is:
scala> case class Foo(a: Int, b: String, c: Double)
defined class Foo
scala> Foo.tupled((1, "bar", 3.14))
res0: Foo = Foo(1,bar,3.14)
You could use pattern matching like:
params match {
case List(x:Int, y:String, d:Double) => Foo(x,y,d)
}
Well, you can certainly do this with a tuple:
(Foo _).tupled apply (1, bar, 3.14)
But there is no real way to get from a List[S] to (A, B, C) for A, B, C <: S. There may be a way of doing this with HLists of course
Another one liner using case class companion object curried method and completely ignoring type safety :)
scala> case class Foo(a: Int, b: String, c: Double)
defined class Foo
scala> val lst = List(1, "bar", 3.14)
lst: List[Any] = List(1, bar, 3.14)
scala> val foo = lst.foldLeft(Foo.curried: Any){case (r, v) => r.asInstanceOf[Function[Any, _]](v) }.asInstanceOf[Foo]
foo: Foo = Foo(1,bar,3.14)