Using Generics To Group A List Of Elements - scala

I'm trying to group elements in a list, when I tried doing this with only one type, the first function works. But when I tried to use generics so I could group elements no matter the type, the function below doesn't do the work. Can you explain how can I do that?
def groupString (list: List[String]): List[List[String]] = {
def groupStringHelper(list: List[String], n: String, outputList:List[List[String]], outputListCurrent: List[String]):List[List[String]] =
if (list.isEmpty) outputList:+ outputListCurrent
else if (list.head == n) groupStringHelper(list.tail, n, outputList, outputListCurrent :+ list.head)
else groupStringHelper(list.tail, list.head, outputList :+outputListCurrent, List(list.head))
groupStringHelper(list, null, List(), null).tail
}
def group [A](list: List[A]): List[List[A]] = {
def groupHelper(list: List[A], n: A, outputList:List[List[A]], currentList: List[A]):List[List[A]] =
if (list.isEmpty) outputList:+ outputListCurrent
else if (list.head == n) groupHelper(list.tail, n, outputList, currentList :+ list.head)
else groupHelper(list.tail, list.head, outputList :+currentList, List(list.head))
groupHelper(list, null, List(), null).tail
}

You would be wise to follow the advice (comment) from #Luis Miguel.
Here's a different approach you could take. (Scala 2.13.x)
def group[A](list: List[A]): List[List[A]] =
List.unfold(list){ lst =>
Option.when(lst.nonEmpty)(lst.span(_ == lst.head))
}

The reason your code not compiled is not all type A is nullable, e.g. Int.
So you can make your code work as:
def group [A >: Null](list: List[A]): List[List[A]] = {
def groupHelper(list: List[A], n: A, outputList:List[List[A]], currentList: List[A]):List[List[A]] =
if (list.isEmpty) outputList:+ currentList
else if (list.head == n) groupHelper(list.tail, n, outputList, currentList :+ list.head)
else groupHelper(list.tail, list.head, outputList :+currentList, List(list.head))
groupHelper(list, null, List(), null).tail
}
However, the above code would not work for group[Int](List(1, 2, 3)).
Here is a solution based on your code with removing null:
def group[A](list: List[A]): List[List[A]] = {
def groupHelper(list: List[A], n: A, outputList:List[List[A]], currentList: List[A]):List[List[A]] =
if (list.isEmpty) outputList:+ currentList
else if (list.head == n) groupHelper(list.tail, n, outputList, currentList :+ list.head)
else groupHelper(list.tail, list.head, outputList :+currentList, List(list.head))
if(list.isEmpty) Nil else groupHelper(list.tail, list.head, Nil, list.take(1))
}

Related

Filter from Seq less/greater elements and only one equal

I want to implement method in Scala which filters from Seq elements which are for example greater than provided value and additionally returns up to one equal element. For example:
greaterOrEqual(Seq(1,2,3,3,4), 3) shouldBe Seq(3,4)
I ended up with such method:
def greaterOrEqual(
seq: ArrayBuffer[Long],
value: Long
): ArrayBuffer[Long] = {
val greater = seq.filter(_ > value)
val equal = seq.filter(_ == value)
if (equal.isEmpty) {
greater
} else {
equal.tail ++ greater
}
}
but somehow it doesn't look nice to me :) Moreover, I'd like to have generic version of this method where I'd able to use not only Long type but custom case classes.
Do you have any suggestions?
Thanks in advance.
def foo[A : Ordering[A]](seq: Seq[A], value: A) = seq.find(_ == value).toList ++ seq.filter(implicitly[Ordering[A]].gt(_,value))
Or (different style)
def foo[A](seq: Seq[A], value: A)(implicit ord: Ordering[A]) = {
import ord._
seq.find(_ == value).toList ++ seq.filter(_ > value)
}
The code below is deprecated
scala> def foo[A <% Ordered[A]](seq: Seq[A], value: A) = seq.find(_ == value).toList ++ seq.filter(_ > value)
foo: [A](seq: Seq[A], value: A)(implicit evidence$1: A => Ordered[A])List[A]
scala> foo(Seq(1,2,3,3,4,4,5),3)
res8: List[Int] = List(3, 4, 4, 5)
Here's my take on it (preserving original order).
import scala.collection.mutable.ArrayBuffer
def greaterOrEqual[A]( seq :ArrayBuffer[A], value :A
)(implicit ord :Ordering[A]
) : ArrayBuffer[A] =
seq.foldLeft((ArrayBuffer.empty[A],true)){
case (acc, x) if ord.lt(x,value) => acc
case ((acc,bool), x) if ord.gt(x,value) => (acc :+ x, bool)
case ((acc,true), x) => (acc :+ x, false)
case (acc, _) => acc
}._1
testing:
greaterOrEqual(ArrayBuffer.from("xawbaxbt"), 'b')
//res0: ArrayBuffer[Char] = ArrayBuffer(x, w, b, x, t)
This is an excellent problem for a simple tail-recursive algorithm over lists.
def greaterOrEqual[T : Ordering](elements: List[T])(value: T): List[T] = {
import Ordering.Implicits._
#annotation.tailrec
def loop(remaining: List[T], alreadyIncludedEqual: Boolean, acc: List[T]): List[T] =
remaining match {
case x :: xs =>
if (!alreadyIncludedEqual && x == value)
loop(remaining = xs, alreadyIncludedEqual = true, x :: acc)
else if (x > value)
loop(remaining = xs, alreadyIncludedEqual, x :: acc)
else
loop(remaining = xs, alreadyIncludedEqual, acc)
case Nil =>
acc.reverse
}
loop(remaining = elements, alreadyIncludedEqual = false, acc = List.empty)
}
Which you can use like this:
greaterOrEqual(List(1, 3, 2, 3, 4, 0))(3)
// val res: List[Int] = List(3, 4)
You can use the below snippet:
val list = Seq(1,2,3,3,4)
val value = 3
list.partition(_>=3)._1.toSet.toSeq
Here partition method divide the list into two list. First list which satisfy the given condition, and second list contains the remaining elements.
For generic method you can using implicit Ordering. Any type who can compare elements can be handled by greaterOrEqual method.
import scala.math.Ordering._
def greaterOrEqual[T](seq: Seq[T], value: T)(implicit ordering: Ordering[T]): Seq[T] = {
#scala.annotation.tailrec
def go(xs: List[T], value: T, acc: List[T]): List[T] = {
xs match {
case Nil => acc
case head :: rest if ordering.compare(head, value) == 0 => rest.foldLeft(head :: acc){
case (result, x) if ordering.compare(x, value) > 0 => x :: result
case (result, _) => result
}
case head :: rest if ordering.compare(head, value) > 0 => go(rest, value, head :: acc)
case _ :: rest => go(rest, value, acc)
}
}
go(seq.toList, value, List.empty[T]).reverse
}

How to replace or append an item in/to a list?

Suppose I've got a list of case class A(id: Int, str: String) and an instance of A. I need to either replace an item from the list with the new instance or append the new instance to the list.
case class A(id: Int, str: String)
def replaceOrAppend(as: List[A], a: A): List[A] = ???
val as = List(A(1, "a1"), A(2, "a2"), A(3, "a3"))
replaceOrAppend(as, A(2, "xyz")) // List(A(1, "a1"), A(2, "xyz"), A(3, "a3"))
replaceOrAppend(as, A(5, "xyz")) // List(A(1, "a1"), A(2, "a2"), A(3, "a3"), A(5, "xyz"))
I can write replaceOrAppend like this:
def replaceOrAppend(as: List[A], a: A): List[A] =
if (as.exists(_.id == a.id)) as.map(x => if (x.id == a.id) a else x) else as :+ a
This implementation is a bit clumsy and obviously suboptimal since it passes the input list twice. How to implement replaceOrAppend to pass the input list just once ?
If the order is not essential I would go with:
def replaceOrAppend(as: List[A], a: A): List[A] =
a::as.filterNot(_.id == a.id)
This would also work if the order is related to id or str:
def replaceOrAppend(as: List[A], a: A): List[A] =
(a::as.filterNot(_.id == a.id)).sortBy(_.id)
And if the order must be kept (as Micheal suggested - I couldn't find anything better):
def replaceOrAppend(as: List[A], a: A): List[A] =
as.span(_.id != a.id) match { case (xs, ys) => xs ++ (a :: ys.drop(1)) }
Here is another one:
def replaceOrAppend(as: List[A], a: A): List[A] = {
as.find(_.id==a.id).map(op => {
as.map(el => el match {
case e if e.id==a.id => e.copy(str=a.str)
case _ => el
})
}).getOrElse((a::as.reverse).reverse)
}
What about this? Still clumsy but only uses one iteration.
def replaceOrAppend(as: List[A], a: A): List[A] = {
val (updatedList,itemToAppend) = as.foldLeft((List[A](),Option(a))) {
case ((acc, Some(item)), l) =>
if (item.id == l.id) (acc :+ item, None)
else (acc :+ l, Some(item))
case ((acc, None), l) => (acc :+ l, None)
}
itemToAppend match {
case Some(item) => updatedList :+ item
case None => updatedList
}
}
I do not understand why people forgets that the best way to handle a functional list is through pattern matching + tail-recursion.
IMHO, this looks cleaner and tries to be as efficient as possible.
final case class A(id: Int, str: String)
def replaceOrAppend(as: List[A], a: A): List[A] = {
#annotation.tailrec
def loop(remaining: List[A], acc: List[A]): List[A] =
remaining match {
case x :: xs if (x.id == a.id) =>
acc reverse_::: (a :: xs)
case x :: xs =>
loop(remaining = xs, acc = x :: acc)
case Nil =>
(a :: acc).reverse
}
loop(remaining = as, acc = List.empty)
}
technically speaking, this traverse the list twice on the worst case.
But, it is always better to build a list by prepending from the head and reverse at the end, than to do many appends.

Implement find and remove in Scala

How is it easier to implement function that find and immutable remove the first occurrence in Scala collection:
case class A(a: Int, b: Int)
val s = Seq(A(1,5), A(4,6), A(2,3), A(5,1), A(2,7))
val (s1, r) = s.findAndRemove(_.a == 2)
Result: s1 = Seq(A(1,5), A(4,6), A(5,1), A(2,7)) , r = Some(A(2,3))
It finds the first element that match, and keeps order. It can be improved with List instead of Seq.
case class A(a: Int, b: Int)
val s = Seq(A(1,5), A(4,6), A(2,3), A(5,1), A(2,7))
val (s1, r) = s.findAndRemove(_.a == 2)
println(s1)
println(r)
implicit class SeqOps[T](s:Seq[T]) {
def findAndRemove(f:T => Boolean):(Seq[T], Option[T]) = {
s.foldLeft((Seq.empty[T], Option.empty[T])) {
case ((l, None), elem) => if(f(elem)) (l, Option(elem)) else (l :+ elem, None)
case ((l, x), elem) => (l :+ elem, x)
}
}
}
Yeah, a little late to the party, but I thought I'd throw this in.
Minimum invocations of the predicate.
Works with most popular collection types: Seq, List, Array, Vector. Even Set and Map (but for those the collection has no order to preserve and there's no telling which element the predicate will find first). Doesn't work for Iterator or String.
-
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
implicit class CollectionOps[U, C[_]](xs :C[U]) {
def findAndRemove(p :U=>Boolean
)(implicit bf :CanBuildFrom[C[U], U, C[U]]
,ev :C[U] => collection.TraversableLike[U, C[U]]
) :(C[U], Option[U]) = {
val (before, after) = xs.span(!p(_))
before ++ after.drop(1) -> after.headOption
}
}
usage:
case class A(a: Int, b: Int)
val (as, a) = Seq(A(1,5), A(4,6), A(2,3), A(5,1), A(2,7)).findAndRemove(_.a==2)
//as: Seq[A] = List(A(1,5), A(4,6), A(5,1), A(2,7))
//a: Option[A] = Some(A(2,3))
val (cs, c) = Array('g','t','e','y','b','e').findAndRemove(_<'f')
//cs: Array[Char] = Array(g, t, y, b, e)
//c: Option[Char] = Some(e)
val (ns, n) = Stream.from(9).findAndRemove(_ > 10)
//ns: Stream[Int] = Stream(9, ?)
//n: Option[Int] = Some(11)
ns.take(5).toList //List[Int] = List(9, 10, 12, 13, 14)
Try something like this
def findAndRemove(as: Seq[A])(fn: A => Boolean): (Seq[A], Option[A]) = {
val index = as.indexWhere(fn)
if(index == -1) as -> None
else as.patch(index, Nil, 1) -> as.lift(index)
}
val (s1, r) = findAndRemove(s)(_.a == 2)
My version:
def findAndRemove(s:Seq[A])(p:A => Boolean):(Seq[A], Option[A])={
val i = s.indexWhere(p)
if(i > 0){
val (l1, l2) = s.splitAt(i)
(l1++l2.tail, Some(l2.head))
}else{
(s, None)
}
}

Recursively iterate through a Scala list

I'm trying to recursively iterate through a list in Scala using pattern matching. I cannot use any list functions, or while/for loops. What I need to do is iterate through the list, and remove an element if it matches to be '4'. I'm new to Scala and I cannot find the answer in the textbook I have nor on google. Everyone else uses the filter method, or some other list method.
Here's what I tried to do (which is wrong)
def removeFours(lst: List[Int]): List[Int] = {
val newLst = lst
lst match {
case Nil => Nil
case a if a == 4 => newLst -= 0
case n => removeFours(newLst)
}
newLst
}
See if this works for you.
def removeFours(lst: List[Int], acc: List[Int] = List.empty): List[Int] = {
lst match {
case Nil => acc.reverse
case 4 :: t => removeFours( t, acc )
case h :: t => removeFours( t, h :: acc )
}
}
Usage:
scala> removeFours( List(3,7,4,9,2,4,1) )
res84: List[Int] = List(3, 7, 9, 2, 1)
Using an inner function and pattern matching to de-structure the list. If the head in the list is 4, then do not add it to the accumulator. If it is, append it to the accumulator.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t =>
if (h == 4) {
loop(t, acc)
}else{
loop(t, acc :+ h)
}
}
loop(lst, List())
}
The preferred way to do this is with guards in the pattern match but the if else statement may look more familiar if you're just getting started with scala.
def removeFours(lst: List[Int]): List[Int] = {
def loop(lst: List[Int], acc: List[Int]): List[Int] = lst match {
case Nil => acc
case h :: t if (h == 4) => loop(t, acc)
case h :: t => loop(t, acc :+ h)
}
loop(lst, List())
}
I am not sure about the execution time. I am also new to scala but I am taking bollean approach to filter any list.
object Main extends App {
//fun that will remove 4
def rm_4(lst: List[Int]) : List[Int] = {
val a = lst.filter(kill_4)
a
}
// boolean fun for conditions
def kill_4(n: Int) : Boolean = {
if (n ==4) false
else true
}
println(rm_4(List(1,2,4,5,4))) // outpur List(1,2,5)
}

scala: implement a generic recursive max function

I'm trying to port this haskell max function implementation to scala
maximum' :: (Ord a) => [a] -> a
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:xs) = max x (maximum' xs)
This is my first attempt:
def max[T <: Ordered[T]](list: List[T]): T = list match {
case Nil => throw new Error("maximum of empty list")
case head :: Nil => head
case list => {
val maxTail = max(list.tail)
if (list.head > maxTail) list.head else maxTail
}
}
max(List[Int](3,4))
But I get the following error:
inferred type arguments [Int] do not conform to method max's type parameter bounds [T <: Ordered[T]]
I tried with ordering, comprable, etc with similar results...
Any idea about what's missing?
Went through a similar exercise as the OP sans pattern matching and generic types, and came up with the following:
def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new NoSuchElementException
if (xs.length == 1)
return xs.head
else
return max(xs.head, max(xs.tail))
}
def max(x: Int, y: Int): Int = if (x > y) x else y
Maybe you want the Ordering type class?
def max[T: Ordering](list: List[T]): T = list match {
case Nil => throw new RuntimeException("maximum of empty list")
case head :: Nil => head
case list =>
val maxTail = max(list.tail)
if (implicitly[Ordering[T]].gt(list.head, maxTail)) list.head else maxTail
}
This is, after all, how the built-in max method works:
// From GenTraversableOnce
def max[A1 >: A](implicit ord: Ordering[A1]): A
You can clean things up a lot if you do this:
def max[T](list: List[T])(implicit ord: Ordering[T]): T = list match {
case Nil => throw new RuntimeException("maximum of empty list")
case head :: Nil => head
case head :: tail => ord.max(head, max(tail))
}
Or, you can make it tail-recursive for increased efficiency (because the compiler will optimize it):
def max[T](list: List[T])(implicit ord: Ordering[T]): T = {
if (list.isEmpty)
throw new RuntimeException("maximum of empty list")
#tailrec
def inner(list: List[T], currMax: T): T =
list match {
case Nil => currMax
case head :: tail => inner(tail, ord.max(head, currMax))
}
inner(list.tail, list.head)
}
Also, you should throw RuntimeException or a subclass of it, not Error.
I have just come up with this solution.
def max(xs: List[Int]): Int = {
if (xs.isEmpty) 0
else {
if( xs.head >= max(xs.tail) ) xs.head
else max(xs.tail)
}
}
I came up with quite a simple solution which is easy to understand. It caters for an empty list, a list with only one element, and negative numbers.
def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new NoSuchElementException
else {
def inner(max: Int, list: List[Int]): Int = {
def compare(x: Int, y: Int): Int =
if (x > y) x
else y
if (list.isEmpty) max
else inner(compare(max, list.head), list.tail)
}
inner(xs.head, xs.tail)
}
}
Oops, shoulda look better before asking
I found the answer in this thread: https://stackoverflow.com/a/691674/47633
It seems like Haskell's type classes are implemented using implicits in scala (like in dhg's example)
so it ends up like this:
def max[T](list: List[T])(implicit f: T => Ordered[T]): T = {
def maxElement(value1: T, value2: T): T = if (value1 > value2) value1 else value2
list match {
case Nil => throw new Error("empty list found")
case head :: Nil => head
case list => maxElement(list.head, max(list.tail))
}
}
or with some syntactic sugar, just
def max[T <% Ordered[T]](list: List[T]): T = list match {
Still, I think the compiler has enough information to do it by himself...
ps: I prettied up a little bit the function...
def genFunc[A](a1: A, a2: A)(f:(A, A) => Boolean):A = if (f(a1, a2)) a1 else a2
def min[A : Ordering] = (a1: A, a2: A) => implicitly[Ordering[A]].lt(a1, a2)
def max[A : Ordering] = (a1: A, a2: A) => implicitly[Ordering[A]].gt(a1, a2)
List(1,2,8,3,4,6,0).reduce(genFunc(_,_)(min))
List(1,2,8,3,4,6,0).reduce(genFunc(_,_)(max))
or if need only function max with tail recursion and the type Option[_] does not break the referential transparency
def max[A: Ordering](list: List[A]): Option[A] = list match {
case Nil => None
case h :: Nil => Some(h)
case h :: t => if(implicitly[Ordering[A]].gt(h, t.head)) max(h :: t.tail) else max(t)
}
max(List(1,2,8,3,4,6,0)).getOrElse("List is empty") // 8: Any
max(List()).getOrElse("List is empty") // List is empty: Any
this is the simplest way I could come up with:
def max(xs: List[Int]): Int = { if (xs.length == 1) xs.head
else if(xs.isEmpty) throw new NoSuchElementException
else if(xs.head > max(xs.tail)) xs.head
else max(xs.tail)} }
this works
def max(xs: List[Int]): Int = xs match{
case Nil => 0
case head :: Nil => head
case head :: tail => max(List(head, max(tail)))
}
My solve:
def max(xs: List[Int]): Int = {
if (xs.isEmpty) 0
else xs.max
}