Scala reduce a List based on a condition - list

I have a List of certain type that I want to reduce based on a condition. I have a type where the Interval is a DateTime interval with a start and an end:
case class MyType(a: Interval, value: Double)
I have got a List[MyType] entries that I want to reduce to a List[MyType] based on MyType that contains same DateTime and value. I do not want to go over the List twice which I already do.
Say I have:
val a = MyType(interval1, 2)
val b = MyType(interval2, 2)
val c = MyType(interval3, 1)
val d = MyType(interval4, 6)
val e = MyType(interval5, 2)
val original = List(a, b, c, d, e)
I have to now reduce the original List based on the following conditions:
1. interval should be continuous, then take the start of the first entry and the end of the second entry
2. the double value should be the same
So assuming that interval1, interval2 are continuous, the result should look like:
val result = Seq(MyType(new Interval(a.interval.start, b.interval.end),2), c, d, e)
Is there a much more elegant solution or an idea?

In the reduce function, check if the condition is true, and if it is, return the current accumulator instead of what would you otherwise compute.
Here's how you would sum only even numbers:
Seq(1,4,6,3).foldLeft(0)( (acc, a) =>
if (a % 2 == 0) acc + a else acc
)
res5: Int = 10
Response to the edited question: It appears you have some conditions that have to hold about the consecuitve elements. Then you can apply the function .sliding.
Seq(a,b,c,d,e).sliding(2).foldLeft(0)(
case (acc, Seq(MyType(ai, a), MyType(bi, b))) =>
if (ai.max == bi.min) acc + a else acc
)
Buuut... You have probably guessed it would not be as performant as you would like. I hope you are not doing any premature optimization, because you know, that's the root of all evil. But if you really need performance, rewrite the code in terms of while loops (fall back to Java).

This should work:
def reduce(xs: List[MyType]) = {
xs match {
case a :: b :: tail =>
if(a.interval.end == b.interval.start && a.value == b.value)
reduce(MyType(new Interval(a.interval.start, b.interval.end) a.value) :: tail)
else
a :: reduce(b :: tail)
case _ => xs
}
}
The if condition might need minor tweaking depending on your exact needs, but the algorithm should work.
Given a list xs
If the first two items a and b can be merged into c, merge them and go back to step 1 with xs = c :: tail
If a and b cannot be merged, try reducing all elements but the first, and append the result to a
Otherwise (list has 1 element or is empty), return xs

Pay attantion that your task could result in multiple distinct solutions, which cannot be further reduced.
So as result you will get a set of solutions: Set[Set[MyType]]
I use Set[MyType] instead of proposed List[MyType] and Seq[MyType] because order is not important and my answer needs possibility to compare different solutions (in order to avoid duplicates).
My answer doesn't make assumptions about order of items, any order is OK.
Besides that in order to simplify the code I have replaced Interval with 2 fields from and to, which can be easily converted.
Here is the code for reduction:
case class MyType(from: Long, to: Long, value: Double)
object MyType {
//Returns all possible varians of reduced source.
//If reduction is not possible, returns empty set.
private def strictReduce(source: Set[MyType]): Set[Set[MyType]] = {
if (source.size <= 1) {Set.empty} else {
val active = source.head //get some item
val otherItems = source.tail //all other items
val reducedWithActive: Set[Set[MyType]] = otherItems.flatMap {
case after if active.to == after.from =>
//we have already found a reduction (active->after),
// so further reductions are not strictly required
reduce(otherItems - after + MyType(active.from, after.to, active.value))
case before if before.to == active.from =>
//we have already found a reduction (before->active),
// so further reductions are not strictly required
reduce(otherItems - before + MyType(before.from, active.to, active.value))
case notContinuos => Set.empty[Set[MyType]]
}
//check if we can reduce items without active
val reducedIgnoringActive = strictReduce(otherItems).
//if so, re-insert active and try to reduce it further, but not strictly anymore
flatMap (reducedOther => reduce(reducedOther + active))
reducedWithActive ++ reducedIgnoringActive
}
}
//Returns all possible varians of reduced source.
//If reduction is not possible, returns source as single result.
private def reduce(source: Set[MyType]): Set[Set[MyType]] = strictReduce(source) match {
case empty if empty.isEmpty => Set(source)
case reduced => reduced
}
//Reduces source, which contains items with different values
def reduceAll(source: Set[MyType]): Set[Set[MyType]] = source.
groupBy(_.value). //divide by values, because they are not merge-able
mapValues(reduce). //reduce for every group
values.reduceLeft((solutionSetForValueA, solutionSetForValueB) =>
//merge solutions for different groups
for(subSolutionForValueA <- solutionSetForValueA;
subSolutionForValueB <- solutionSetForValueB)
yield (subSolutionForValueA ++ subSolutionForValueB) //merge subSolutions
)
}
And here is the sample, which uses it:
object Example extends App {
val source = Set(
MyType(0L, 1L, 1.0),
MyType(1L, 2L, 2.0), //different value
MyType(1L, 3L, 1.0), //competing with next
MyType(1L, 4L, 1.0), //competing with prev
MyType(3L, 5L, 1.0), //joinable with pre-prev
MyType(2L, 4L, 2.0), //joinable with second
MyType(0L, 4L, 3.0) //lonely
)
val solutions: Set[Set[MyType]] = MyType.reduceAll(source)
//here you could choose the best solution (for example by size)
//printing out
solutions.foreach(solution => println(solution.toList.sortBy(_.from).sortBy(_.value).
map(item => s"${item.from}->${item.to}(${item.value})").mkString(", ")))
}
My result is:
0->5(1.0), 1->4(1.0), 1->4(2.0), 0->4(3.0)
0->4(1.0), 1->5(1.0), 1->4(2.0), 0->4(3.0)

Here is what I came up with:
def reduce(accumulator: Seq[MyType], original: Seq[MyType]): Seq[MyType] = original match {
case Nil => accumulator
case head :: xs => {
val found = xs.find(_.timeSpan.getStart().equals(head.timeSpan.getEnd))
if (found.isDefined && found.get.value == head.value) {
reduce(
accumulator :+ (MyType(new Interval(head.timeSpan.getStart, found.get.timeSpan.getEnd), head.value)),
original.diff(Seq(found.get, head))
)
}
else
reduce(
accumulator :+ head,
xs
)
}
}

Related

How to access an element of list within a list in scala

I want to access elements of a list within one list and check whether the elements are greater than a minimum value.
Example: List[([1,2],0.3), ([1.5,6],0.35), ([4,10],0.25), ([7,15],0.1)]
Let the minimum value: 1
The result should be: List[([1,6],0.65), ([4,10],0.25), ([7,15],0.1)]
As 1.5-1 is less than minimum value 1, it will merge the elements [1,2],0.3) and ([1.5,6],0.35) as [1, 6], 0.65, meaning it will take the 1st element of the inside list and last element of the 2nd element of the outside list and the 2nd element of the outside list will be added (0.3+0.35). This will be done for all elements of the outside list.
The code I tried is written below:
def reduce (d1:List[(Interval, Rational)]): List[(Interval, Rational)] =
{
var z = new ListBuffer[(Interval, Rational)]()
def recurse (list: List[(Interval, Rational)]): Unit = list match {
case List(x, y, _*) if ((y._1_1 - x._1_1) < min_val) =>
val i = x._1_1; y._1_2
val w = x._2 + y._2
z += (i,w)
else
z += x
recurse(list.tail)
case Nil =>
}
z.toList
}
But this is not working. Please help me to fix this.
OK, what you've written really isn't Scala code, and I had to make a few modifications just to get a compilable example, but see if this works for you.
type Interval = (Double,Double)
type Rational = Double
def reduce (lir:List[(Interval, Rational)]): List[(Interval, Rational)] = {
val minVal = 1.0
lir.foldLeft(List.empty[(Interval, Rational)]){
case (a, b) if a.isEmpty => List(b)
case (acc, ((i2a, i2b), r2)) =>
val ((i1a, _), r1) = acc.head
if (i2a - i1a < minVal) ((i1a, i2b), r1 + r2) :: acc.tail
else ((i2a, i2b), r2) :: acc
}.reverse
}
Test case:
reduce(List( ((1.0,2.0),0.3), ((1.5,6.0),0.35), ((4.0,10.0),0.25), ((7.0,15.0),0.1) ))
// result: List[(Interval, Rational)] = List(((1.0,6.0),0.6499999999999999), ((4.0,10.0),0.25), ((7.0,15.0),0.1))

How to find the largest element in a list of integers recursively?

I'm trying to write a function which will recursively find the largest element in a list of integers. I know how to do this in Java, but can't understand how to do this at Scala.
Here is what I have so far, but without recursion:
def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new java.util.NoSuchElementException();
else xs.max;
}
How can we find it recursively with Scala semantic.
This is the most minimal recursive implementation of max I've ever been able to think up:
def max(xs: List[Int]): Option[Int] = xs match {
case Nil => None
case List(x: Int) => Some(x)
case x :: y :: rest => max( (if (x > y) x else y) :: rest )
}
It works by comparing the first two elements on the list, discarding the smaller (or the first, if both are equal) and then calling itself on the remaining list. Eventually, this will reduce the list to one element which must be the largest.
I return an Option to deal with the case of being given an empty list without throwing an exception - which forces the calling code to recognise the possibility and deal with it (up to the caller if they want to throw an exception).
If you want it to be more generic, it should be written like this:
def max[A <% Ordered[A]](xs: List[A]): Option[A] = xs match {
case Nil => None
case x :: Nil => Some(x)
case x :: y :: rest => max( (if (x > y) x else y) :: rest )
}
Which will work with any type which either extends the Ordered trait or for which there is an implicit conversion from A to Ordered[A] in scope. So by default it works for Int, BigInt, Char, String and so on, because scala.Predef defines conversions for them.
We can become yet more generic like this:
def max[A <% Ordered[A]](xs: Seq[A]): Option[A] = xs match {
case s if s.isEmpty || !s.hasDefiniteSize => None
case s if s.size == 1 => Some(s(0))
case s if s(0) <= s(1) => max(s drop 1)
case s => max((s drop 1).updated(0, s(0)))
}
Which will work not just with lists but vectors and any other collection which extends the Seq trait. Note that I had to add a check to see if the sequence actually has a definite size - it might be an infinite stream, so we back away if that might be the case. If you are sure your stream will have a definite size, you can always force it before calling this function - it's going to work through the whole stream anyway. See notes at the end for why I really would not want to return None for an indefinite stream, though. I'm doing it here purely for simplicity.
But this doesn't work for sets and maps. What to do? The next common supertype is Iterable, but that doesn't support updated or anything equivalent. Anything we construct might be very poorly performing for the actual type. So my clean no-helper-function recursion breaks down. We could change to using a helper function but there are plenty of examples in the other answers and I'm going to stick with a one-simple-function approach. So at this point, we can to switch to reduceLeft (and while we are at it, let's go for `Traversable' and cater for all collections):
def max[A <% Ordered[A]](xs: Traversable[A]): Option[A] = {
if (xs.hasDefiniteSize)
xs reduceLeftOption({(b, a) => if (a >= b) a else b})
else None
}
but if you don't consider reduceLeft recursive, we can do this:
def max[A <% Ordered[A]](xs: Traversable[A]): Option[A] = xs match {
case i if i.isEmpty => None
case i if i.size == 1 => Some(i.head)
case i if (i collect { case x if x > i.head => x }).isEmpty => Some(i.head)
case _ => max(xs collect { case x if x > xs.head => x })
}
It uses the collect combinator to avoid some clumsy method of bodging a new Iterator out of xs.head and xs drop 2.
Either of these will work safely with almost any collection of anything which has an order. Examples:
scala> max(Map(1 -> "two", 3 -> "Nine", 8 -> "carrot"))
res1: Option[(Int, String)] = Some((8,carrot))
scala> max("Supercalifragilisticexpialidocious")
res2: Option[Char] = Some(x)
I don't usually give these others as examples, because it requires more expert knowledge of Scala.
Also, do remember that the basic Traversable trait provides a max method, so this is all just for practice ;)
Note: I hope that all my examples show how careful choice of the sequence of your case expressions can make each individual case expression as simple as possible.
More Important Note: Oh, also, while I am intensely comfortable returning None for an input of Nil, in practice I'd be strongly inclined to throw an exception for hasDefiniteSize == false. Firstly, a finite stream could have a definite or non-definite size dependent purely on the sequence of evaluation and this function would effectively randomly return Option in those cases - which could take a long time to track down. Secondly, I would want people to be able to differentiate between having passed Nil and having passed truly risk input (that is, an infinite stream). I only returned Option in these demonstrations to keep the code as simple as possible.
The easiest approach would be to use max function of TraversableOnce trait, as follows,
val list = (1 to 10).toList
list.max
to guard against the emptiness you can do something like this,
if(list.empty) None else Some(list.max)
Above will give you an Option[Int]
My second approach would be using foldLeft
(list foldLeft None)((o, i) => o.fold(Some(i))(j => Some(Math.max(i, j))))
or if you know a default value to be returned in case of empty list, this will become more simpler.
val default = 0
(list foldLeft default)(Math.max)
Anyway since your requirement is to do it in recursive manner, I propose following,
def recur(list:List[Int], i:Option[Int] = None):Option[Int] = list match {
case Nil => i
case x :: xs => recur(xs, i.fold(Some(x))(j => Some(Math.max(j, x))))
}
or as default case,
val default = 0
def recur(list:List[Int], i:Int = default):Int = list match {
case Nil => i
case x :: xs => recur(xs, i.fold(x)(j => Math.max(j, x)))
}
Note that, this is tail recursive. Therefore stack is also saved.
If you want functional approach to this problem then use reduceLeft:
def max(xs: List[Int]) = {
if (xs.isEmpty) throw new NoSuchElementException
xs.reduceLeft((x, y) => if (x > y) x else y)
}
This function specific for list of ints, if you need more general approach then use Ordering typeclass:
def max[A](xs: List[A])(implicit cmp: Ordering[A]): A = {
if (xs.isEmpty) throw new NoSuchElementException
xs.reduceLeft((x, y) => if (cmp.gteq(x, y)) x else y)
}
reduceLeft is a higher-order function, which takes a function of type (A, A) => A, it this case it takes two ints, compares them and returns the bigger one.
You could use pattern matching like that
def max(xs: List[Int]): Int = xs match {
case Nil => throw new NoSuchElementException("The list is empty")
case x :: Nil => x
case x :: tail => x.max(max(tail)) //x.max is Integer's class method
}
Scala is a functional language whereby one is encourage to think recursively. My solution as below. I recur it base on your given method.
def max(xs: List[Int]): Int = {
if(xs.isEmpty == true) 0
else{
val maxVal= max(xs.tail)
if(maxVal >= xs.head) maxVal
else xs.head
}
}
Updated my solution to tail recursive thanks to suggestions.
def max(xs: List[Int]): Int = {
def _max(xs: List[Int], maxNum: Int): Int = {
if (xs.isEmpty) maxNum
else {
val max = {
if (maxNum >= xs.head) maxNum
else xs.head
}
_max(xs.tail, max)
}
}
_max(xs.tail, xs.head)
}
I used just head() and tail()
def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new NoSuchElementException
else maxRecursive(xs.tail, xs.head)
}
def maxRecursive(xs: List[Int], largest: Int): Int = {
if (!xs.isEmpty) {
if (xs.head > largest) maxRecursive(xs.tail, xs.head)
else maxRecursive(xs.tail, largest)
} else {
largest
}
}
Here is tests for this logic:
test("max of a few numbers") {
assert(max(List(3, 7, 2, 1, 10)) === 10)
assert(max(List(3, -7, 2, -1, -10)) === 3)
assert(max(List(-3, -7, -2, -5, -10)) === -2)
}
Folding can help:
if(xs.isEmpty)
throw new NoSuchElementException
else
(Int.MinValue /: xs)((max, value) => math.max(max, value))
List and pattern matching (updated, thanks to #x3ro)
def max(xs:List[Int], defaultValue: =>Int):Int = {
#tailrec
def max0(xs:List[Int], maxSoFar:Int):Int = xs match {
case Nil => maxSoFar
case head::tail => max0(tail, math.max(maxSoFar, head))
}
if(xs.isEmpty)
defaultValue
else
max0(xs, Int.MinValue)
}
(This solution does not create Option instance every time. Also it is tail-recursive and will be as fast as an imperative solution.)
Looks like you're just starting out with scala so I try to give you the simplest answer to your answer, how do it recursively:
def max(xs: List[Int]): Int = {
def maxrec(currentMax : Int, l: List[Int]): Int = l match {
case Nil => currentMax
case head::tail => maxrec(head.max(currentMax), tail) //get max of head and curretn max
}
maxrec(xs.head, xs)
}
This method defines an own inner method (maxrec) to take care of the recursiveness. It will fail ( exception) it you give it an empty list ( there's no maximum on an empty List)
Here is my code (I am a newbie in functional programming) and I'm assuming whoever lands up under this question will be folks like me. The top answer, while great, is bit too much for newbies to take! So, here is my simple answer. Note that I was asked (as part of a Course) to do this using only head and tail.
/**
* This method returns the largest element in a list of integers. If the
* list `xs` is empty it throws a `java.util.NoSuchElementException`.
*
* #param xs A list of natural numbers
* #return The largest element in `xs`
* #throws java.util.NoSuchElementException if `xs` is an empty list
*/
#throws(classOf[java.util.NoSuchElementException])
def max(xs: List[Int]): Int = find_max(xs.head, xs.tail)
def find_max(max: Int, xs: List[Int]): Int = if (xs.isEmpty) max else if (max >= xs.head) find_max(max, xs.tail) else find_max(xs.head, xs.tail)
Some tests:
test("max of a few numbers") {
assert(max(List(3, 7, 2)) === 7)
intercept[NoSuchElementException] {
max(List())
}
assert(max(List(31,2,3,-31,1,2,-1,0,24,1,21,22)) === 31)
assert(max(List(2,31,3,-31,1,2,-1,0,24,1,21,22)) === 31)
assert(max(List(2,3,-31,1,2,-1,0,24,1,21,22,31)) === 31)
assert(max(List(Int.MaxValue,2,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,222,3,-31,1,2,-1,0,24,1,21,22)) === Int.MaxValue)
}
list.sortWith(_ > ).head & list.sortWith( > _).reverse.head for greatest and smallest number
If you are required to write a recursive max function on a list using isEmpty, head and tail and throw exception for empty list:
def max(xs: List[Int]): Int =
if (xs.isEmpty) throw new NoSuchElementException("max of empty list")
else if (xs.tail.isEmpty) xs.head
else if (xs.head > xs.tail.head) max(xs.head :: xs.tail.tail)
else max(xs.tail)
if you were to use max function on list it is simply (you don't need to write your own recursive function):
val maxInt = List(1, 2, 3, 4).max
def max(xs: List[Int]): Int = {
def _max(xs: List[Int], maxAcc:Int): Int = {
if ( xs.isEmpty )
maxAcc
else
_max( xs.tail, Math.max( maxAcc, xs.head ) ) // tail call recursive
}
if ( xs.isEmpty )
throw new NoSuchElementException()
else
_max( xs, Int.MinValue );
}
With tail-recursion
#tailrec
def findMax(x: List[Int]):Int = x match {
case a :: Nil => a
case a :: b :: c => findMax( (if (a > b) a else b) ::c)
}
With pattern matching to find max and return zero in case empty
def findMax(list: List[Int]) = {
def max(list: List[Int], n: Int) : Int = list match {
case h :: t => max(t, if(h > n) h else n)
case _ => n
}
max(list,0)
}
I presume this is for the progfun-example
This is the simplest recursive solution I could come up with
def max(xs: List[Int]): Int = {
if (xs.isEmpty) throw new NoSuchElementException("The list is empty")
val tail = xs.tail
if (!tail.isEmpty) maxOfTwo(xs.head, max(xs.tail))
else xs.head
}
def maxOfTwo(x: Int, y: Int): Int = {
if (x >= y) x
else y
}
def max(xs: List[Int]): Int = xs match {
case Nil => throw new NoSuchElementException("empty list!")
case x :: Nil => x
case x :: tail => if (x > max(tail)) x else max(tail)
}

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 should I remove the first occurrence of an object from a list in Scala?

What is the best way to remove the first occurrence of an object from a list in Scala?
Coming from Java, I'm accustomed to having a List.remove(Object o) method that removes the first occurrence of an element from a list. Now that I'm working in Scala, I would expect the method to return a new immutable List instead of mutating a given list. I might also expect the remove() method to take a predicate instead of an object. Taken together, I would expect to find a method like this:
/**
* Removes the first element of the given list that matches the given
* predicate, if any. To remove a specific object <code>x</code> from
* the list, use <code>(_ == x)</code> as the predicate.
*
* #param toRemove
* a predicate indicating which element to remove
* #return a new list with the selected object removed, or the same
* list if no objects satisfy the given predicate
*/
def removeFirst(toRemove: E => Boolean): List[E]
Of course, I can implement this method myself several different ways, but none of them jump out at me as being obviously the best. I would rather not convert my list to a Java list (or even to a Scala mutable list) and back again, although that would certainly work. I could use List.indexWhere(p: (A) ⇒ Boolean):
def removeFirst[E](list: List[E], toRemove: (E) => Boolean): List[E] = {
val i = list.indexWhere(toRemove)
if (i == -1)
list
else
list.slice(0, i) ++ list.slice(i+1, list.size)
}
However, using indices with linked lists is usually not the most efficient way to go.
I can write a more efficient method like this:
def removeFirst[T](list: List[T], toRemove: (T) => Boolean): List[T] = {
def search(toProcess: List[T], processed: List[T]): List[T] =
toProcess match {
case Nil => list
case head :: tail =>
if (toRemove(head))
processed.reverse ++ tail
else
search(tail, head :: processed)
}
search(list, Nil)
}
Still, that's not exactly succinct. It seems strange that there's not an existing method that would let me do this efficiently and succinctly. So, am I missing something, or is my last solution really as good as it gets?
You can clean up the code a bit with span.
scala> def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
| val (before, atAndAfter) = list span (x => !pred(x))
| before ::: atAndAfter.drop(1)
| }
removeFirst: [T](list: List[T])(pred: T => Boolean)List[T]
scala> removeFirst(List(1, 2, 3, 4, 3, 4)) { _ == 3 }
res1: List[Int] = List(1, 2, 4, 3, 4)
The Scala Collections API overview is a great place to learn about some of the lesser known methods.
This is a case where a little bit of mutability goes a long way:
def withoutFirst[A](xs: List[A])(p: A => Boolean) = {
var found = false
xs.filter(x => found || !p(x) || { found=true; false })
}
This is easily generalized to dropping the first n items matching the predicate. (i<1 || { i = i-1; false })
You can also write the filter yourself, though at this point you're almost certainly better off using span since this version will overflow the stack if the list is long:
def withoutFirst[A](xs: List[A])(p: A => Boolean): List[A] = xs match {
case x :: rest => if (p(x)) rest else x :: withoutFirst(rest)(p)
case _ => Nil
}
and anything else is more complicated than span without any clear benefits.

Scala insert into list at specific locations

This is the problem that I did solve, however being a total imperative Scala noob, I feel I found something totally not elegant. Any ideas of improvement appreciated.
val l1 = 4 :: 1 :: 2 :: 3 :: 4 :: Nil // original list
val insert = List(88,99) // list I want to insert on certain places
// method that finds all indexes of a particular element in a particular list
def indexesOf(element:Any, inList:List[Any]) = {
var indexes = List[Int]()
for(i <- 0 until inList.length) {
if(inList(i) == element) indexes = indexes :+ i
}
indexes
}
var indexes = indexesOf(4, l1) // get indexes where 4 appears in the original list
println(indexes)
var result = List[Any]()
// iterate through indexes and insert in front
for(i <- 0 until indexes.length) {
var prev = if(i == 0) 0 else indexes(i-1)
result = result ::: l1.slice(prev, indexes(i)) ::: insert
}
result = result ::: l1.drop(indexes.last) // append the last bit from original list
println(result)
I was thinking more elegant solution would be achievable with something like this, but that's just pure speculation.
var final:List[Any] = (0 /: indexes) {(final, i) => final ::: ins ::: l1.slice(i, indexes(i))
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = {
xs.map(x => if (p(x)) extra ::: List(x) else List(x)).flatten
}
scala> insert(List(4,1,2,3,4),List(88,99)){_ == 4}
res3: List[Int] = List(88, 99, 4, 1, 2, 3, 88, 99, 4)
Edit: explanation added.
Our goal here is to insert a list (called extra) in front of selected elements in another list (here called xs--commonly used for lists, as if one thing is x then lots of them must be the plural xs). We want this to work on any type of list we might have, so we annotate it with the generic type [A].
Which elements are candidates for insertion? When writing the function, we don't know, so we provide a function that says true or false for each element (p: A => Boolean).
Now, for each element in the list x, we check--should we make the insertion (i.e. is p(x) true)? If yes, we just build it: extra ::: List(x) is just the elements of extra followed by the single item x. (It might be better to write this as extra :+ x--add the single item at the end.) If no, we have only the single item, but we make it List(x) instead of just x because we want everything to have the same type. So now, if we have something like
4 1 2 3 4
and our condition is that we insert 5 6 before 4, we generate
List(5 6 4) List(1) List(2) List(3) List(5 6 4)
This is exactly what we want, except we have a list of lists. To get rid of the inner lists and flatten everything into a single list, we just call flatten.
The flatten trick is cute, I wouldn't have thought of using map here myself. From my perspective this problem is a typical application for a fold, as you want go through the list and "collect" something (the result list). As we don't want our result list backwards, foldRight (a.k.a. :\) is here the right version:
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) =
xs.foldRight(List[A]())((x,xs) => if (p(x)) extra ::: (x :: xs) else x :: xs)
Here's another possibility, using Seq#patch to handle the actual inserts. You need to foldRight so that later indices are handled first (inserts modify the indices of all elements after the insert, so it would be tricky otherwise).
def insert[A](xs: Seq[A], ys: Seq[A])(pred: A => Boolean) = {
val positions = xs.zipWithIndex filter(x => pred(x._1)) map(_._2)
positions.foldRight(xs) { (pos, xs) => xs patch (pos, ys, 0) }
}