I have a seq
val seq = Seq(1, 9, 5, 4, 3, 5, 5, 5, 8, 2)
I want to get an average for each adjacent (left and right) numbers, meaning in the above example to have the following calculations:
[(1+9)/2, (1+9+5)/3, (9+5+4)/3, (5+4+3)/3, (4+3+5)/3, (3+5+5)/3, (5+5+5)/3, (5+5+8)/3, (5+8+2)/3, (8+2)/2]
The other examples are:
Seq() shouldBe Seq()
Seq(3) shouldBe Seq(3.0d)
Seq(1, 4) shouldBe Seq(2.5d, 2.5d)
Seq(1, 9, 5, 4, 3, 5, 5, 5, 8, 2) shouldBe Seq(5.0, 5.0, 6.0, 4.0, 4.0, 13.0 / 3, 5.0, 6.0, 5.0, 5.0)
I was able to get: numbers.sliding(2, 1).map(nums => nums.sum.toDouble / nums.length).toSeq. But it doesn't consider the previous value.
I tried to do it with foldLeft - it is also cumbersome.
Is there an easy way to do this? What am I missing?
Being honest, this is the kind of problems that I believe are easier to solve using a simple (albeit a bit long) tail-recursive algorithm.
def adjacentAverage(data: List[Int]): List[Double] = {
#annotation.tailrec
def loop(remaining: List[Int], acc: List[Double], previous: Int): List[Double] =
remaining match {
case x :: y :: xs =>
loop(
remaining = y :: xs,
((previous + x + y).toDouble / 3.0d) :: acc,
previous = x
)
case x :: Nil =>
(((previous + x).toDouble / 2.0d) :: acc).reverse
}
data match {
case x :: y :: xs => loop(remaining = y :: xs, acc = ((x + y).toDouble / 2.0d) :: Nil, previous = x)
case x :: Nil => x.toDouble :: Nil
case Nil => Nil
}
}
You can see it running here.
What if you want a sliding window of a different size, like maybe 4 or 7 or ...? The challenge is getting the build-up, (1), (1,2), (1,2,3), (1,2,3,4), ... and the tail-off, ..., (6,7,8,9), (7,8,9), (8,9), (9).
def windowAvg(input: Seq[Int], windowSize: Int): Seq[Double] =
if (input.isEmpty || windowSize < 1) Seq()
else {
val windows = input.sliding(windowSize).toSeq
val buildUp = windows.head.inits.toSeq.tail.reverse.tail
val tailOff = windows.last.tails.toSeq.tail.init
(buildUp ++ windows ++ tailOff).map(x => x.sum.toDouble / x.length)
}
If you really need to trim off the opening and ending single-number entries in the result, then I'll leave that as an exercise for the reader.
My cumbersome solution through foldLeft (no rocket science)
def adjacentAverage(numbers: Seq[Int]): Seq[Double] = numbers.foldLeft(("x", Seq[Double](), 0)) {(acc, num) => acc._1 match {
case "x" => if (numbers.isEmpty) ("x", Seq(), acc._3 + 1) else if (numbers.length == 1) ("x", Seq(num.toDouble), acc._3 + 1) else (num.toString, acc._2 :+ ((num.toDouble + numbers(acc._3 + 1).toDouble) / 2.0), acc._3 + 1)
case _ => (num.toString, try {acc._2 :+ ((acc._1.toDouble + num.toDouble + numbers(acc._3 + 1).toDouble) / 3.0)} catch {case e: IndexOutOfBoundsException => acc._2 :+ ((acc._1.toDouble + num.toDouble) / 2.0) }, acc._3 + 1)
}}._2
Related
I've written the following method (working perfectly fine) which takes a list and returns a list of lists containing the
elements, so that the first list contains half of list’s elements, the next contains half of the remaining elements, and so on. For example,
repHalve(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15))
Returning:
List(List(1, 2, 3, 4, 5, 6, 7, 8), List(9, 10, 11, 12), List(13, 14), List(15))
The question is I'm new to Scala and wanted to convert this method to recursive approach. Please let me know how should I convert this. I know the base case could be the same as the condition inside while loop but still unable to figure it out. Any help would be highly appreciated. Thanks
def repHalve(list:List[Any]){
var local_list:List[Any] = list
var list_of_lists:List[Any] = List.empty
while(local_list.length>1){
val sub = local_list.slice(0, (local_list.length/2)+1)
list_of_lists ++= List(sub)
local_list = local_list.slice(local_list.length/2+1, local_list.length)
}
list_of_lists ++= List(List(list.last))
println(list_of_lists)
}
Consider analogous solution to Luis' but using splitAt
def repHalve(l: List[Int]): List[List[Int]] = {
def half(i: Int): Int = if ((i % 2) == 0) i / 2 else (i + 1) / 2
#annotation.tailrec
def loop(l: List[Int], size: Int, acc: List[List[Int]]): List[List[Int]] = l match {
case x :: Nil => (List(x) :: acc).reverse
case _ =>
val (left, right) = l.splitAt(half(size))
loop(right, right.size, left :: acc)
}
loop(l, l.size, Nil)
}
jmh benchmark using (1 to 200).toList as input indicates Luis' solution is faster
[info] So60178352._luis thrpt 5 666357.490 ± 165323.129 ops/s
[info] So60178352._mario thrpt 5 591174.959 ± 118097.426 ops/s
Here is a completely tail-recursive implementation.
Let me know if you have any questions.
def repHalve[T](list: List[T]): List[List[T]] = {
def half(i: Int): Int =
if ((i % 2) == 0) i / 2 else (i + 1) / 2
#annotation.tailrec
def loop(remaining: List[T], targetLength: Int, acc: List[List[T]]): List[List[T]] =
remaining match {
case Nil => acc.reverse
case list =>
#annotation.tailrec
def innerLoop(remaining: List[T], currentLength: Int, acc: List[T]): (List[T], List[T]) =
remaining match {
case x :: xs =>
if (currentLength != targetLength)
innerLoop(remaining = xs, currentLength + 1, x :: acc)
else
(x :: xs, acc.reverse)
case Nil =>
(Nil, acc.reverse)
}
val (remaining, newList) = innerLoop(remaining = list, currentLength = 0, acc = List.empty)
loop(remaining, half(targetLength), newList :: acc)
}
loop(remaining = list, targetLength = half(list.length), acc = List.empty)
}
Which you can use like this:
repHalve((1 to 20).toList)
// res: List[List[Int]] = List(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), List(11, 12, 13, 14, 15), List(16, 17, 18), List(19, 20))
I'm trying to swap first 2 elements in a List using the below function.
def swap_list(a:List[Int]):List[Int]={
a match {
case x::y::Nil => List(y,x)
case List(x,y,rest # _*) => List(y,x)
case _ => a
}
}
swap_list(List(10,20,30))
This works. However, If I try to include the rest I'm getting a error like
case List(x,y,rest # _*) => List(y,x) +: rest
Error below
Error:(27, 50) type mismatch;
found : Seq[Any]
required: List[Int]
case List(x,y,rest # _*) => List(y,x) +: rest
when I'm specifying the function result type in the definition, why am I getting Seq[Any] in the error message?
I need to return List(20,10,30). How to resolve this?.
Apparently operators in scala List are confusing. You need to concat lists using ++,
def swap_list(a:List[Int]):List[Int]={
a match {
case x::y::Nil => List(y,x)
case List(x,y,rest # _*) => List(y,x) ++ rest
case _ => a
}
}
val newList = swap_list(List(10, 20, 30))
println(newList) //List(20, 10, 30)
Summary of List operators,
1) prepend on List using +: or ::
scala> 1000 +: List(1, 2, 3)
res1: List[Int] = List(1000, 1, 2, 3)
scala> 1000 :: List(1, 2, 3)
res4: List[Int] = List(1000, 1, 2, 3)
2) append on List using :+
scala> List(1, 2, 3) :+ 100
res2: List[Int] = List(1, 2, 3, 100)
3) concat Lists using ++, same as in haskell
scala> List(1, 2, 3) ++ List(4, 5, 6)
res3: List[Int] = List(1, 2, 3, 4, 5, 6)
Well, while prayagupd solution works, and clearly explains the problem (and should be the accepted answer IMHO).
I think is worth sharing a "better" solution to this problem, since concatenating lists is expensive, it is better to just prepend elements to them.
def swapList[T](l: List[T]): List[T] = l match {
case Nil => Nil
case x :: Nil => x :: Nil
case x :: y :: xs => y :: x :: xs
}
swapList(List(10,20,30)) // res0: List[Int] = List(20, 10, 30).
You need to ++ instead of +: as the latter is for single element.
The simplest implementation is this:
def swap_list(a: List[Int]): List[Int] =
a match {
case x :: y :: tail => y :: x :: tail
case _ => a
}
I have:
val a = List((1.1, 2), (1.2, 3), (3.1, 4), (2.9, 5))
I want to group this list with "eligible deviation", or in other words: group every double with doubles that are bigger/smaller than itself.
The result I want (Let's say that the eligible deviation here is 0.2):
Map((1.1, 1.2) -> List((1.1, 2),(1.2, 3)), (3.1, 2.9) -> List((3.1, 4), (2.9, 5)))
How can I do this?
Not sure if this is exactly what you want:
// sort the list by the first element in each tuple
val sort_a = a.sortBy(_._1)
// calculate the difference of consecutive tuples by the first element
val diff = sort_a.scanLeft((0.0, 0.0))((x,y) => (y._1 - x._2, y._1)).tail
// create a group variable based on the difference and tolerance
val g = diff.scanLeft(0)((x, y) => if(y._1 < 0.201) x else x + 1).tail
// g: List[Int] = List(1, 1, 2, 2)
// zip the list and the group variable and split the list up by the group variable
sort_a.zip(g).groupBy(_._2).mapValues(_.map(_._1))
// res62: scala.collection.immutable.Map[Int,List[(Double, Int)]] =
// Map(2 -> List((2.9,5), (3.1,4)), 1 -> List((1.1,2), (1.2,3)))
Here is a (tail)recursive implementation. The main difference with using scan and the Collections API is that the compiler de-sugar this to a while-loop which typically runs pretty fast.
import scala.annotation.tailrec
def grouper(seq: List[(Double,Int)], delta: Double): Map[List[Double], List[(Double,Int)]] = {
#tailrec def loop(rest: List[(Double,Int)], last: Double, curGroup: List[(Double,Int)], allGroups: List[List[(Double,Int)]]): List[List[(Double,Int)]] = {
rest match {
case h::t if Math.abs( h._1 - last ) <= delta => loop(t, h._1, h :: curGroup, allGroups)
case h::t => loop(t, h._1, h :: Nil, if(curGroup.nonEmpty) curGroup :: allGroups else allGroups)
case _ => if(curGroup.nonEmpty) curGroup :: allGroups else allGroups
}
}
val list = loop(seq, Double.NegativeInfinity, List.empty, List.empty)
list.map(x => (x.map(_._1), x)).toMap
}
Using it:
> grouper(List((1.1, 2), (1.2, 3), (1.3, 4), (2.9, 5)), 0.2)
res1: Map[List[Double], List[(Double, Int)]] = Map(List(2.9) -> List((2.9, 5)), List(1.3, 1.2, 1.1) -> List((1.3, 4), (1.2, 3), (1.1, 2)))
Imagine I have an unsorted list of positive & negative ints. I want to return a list containing all the positive ints, and the first negative number, but then ignore all subsequent negative numbers from the list, while preserving the ordering.
Imperatively I could do:
l = [1, 2, -4, 5, -6, -1, 3]
out = []
first = true
for n in l:
if n >= 0:
out.push(n)
else if first:
out.push(n)
first = false
// out = [1, 2, -4, 5, 3]
How could I do this with FP in Scala? I was thinking (probably won't compile...):
val l = List(1, 2, -4, 5, -6, -1, 3)
val posl = l.map(_ >= 0)
val negl = l.zipWithIndex.map((n, i) => if (n < 0) (i, n) else (None, None)).head
// now split posl at negl._1, and create a new list of leftSlice :: negl._2 :: rightSlice?
Is this the right approach, or is there a more elegant, succinct way?
It wouldn't be a proper functional programming question without a slightly-too-clever recursion+pattern matching answer.
def firstNegAllPos(l:List[Int]):List[Int] = {
l match{
case x::xs if x>=0 => x::firstNegAllPos(xs)
case x::xs if x<0 => x::xs.filter(_>=0)
case Nil => Nil
}
}
Here is a tail-recursive way. Compared to m-z's answer, it iterates your list only one time, compared to Dimas answer, it does not use mutable state, so it is pure functional.
def firstNegAllPos(list: List[Int]) : List[Int] = {
def loop(in: List[Int], out: List[Int], negfound: Boolean) : List [Int] = {
in match {
case Nil => out
case head :: tail =>
if (negfound)
loop(tail, if (head < 0) out else head :: out, true)
else
loop(tail, head :: out, head < 0)
}
}
loop(list, Nil, false)
}
firstNegAllPos(List(1, 2, -4, 5, -6, -1, 3)) // List(3, 5, -4, 2, 1)
Edit:
The above implementation provides a reversed result. In order to preserve order you can do following:
def firstNegAllPos(list: List[Int]) : List[Int] = {
def loop(in: List[Int], out: List[Int], negfound: Boolean) : List [Int] = {
in match {
case Nil => out
case head :: tail =>
if (negfound)
loop(tail, if (head < 0) out else head :: out, true)
else
loop(tail, head :: out, head < 0)
}
}
loop(list, Nil, false).reverse
}
firstNegAllPos(List(1, 2, -4, 5, -6, -1, 3)) // List(1, 2, -4, 5, 3)
You can do it in one pass provided you don't mind keeping a bit of state around - mind the var neg:
var neg = false
list.filter {
case x if x > 0 => true
case _ if !neg => neg = true
}
A direct translation of the requirement is pretty clear, takes one pass over the list, and is functional:
val l = List(1, 2, -4, 5, -6, -1, 3)
// split into any initial positive numbers, and the rest of the list
val (pos, firstneg) = l.span(_ >= 0)
// if there were no negative numbers, return the original list.
// otherwise, it's the initial positives, the first negative, and
// the positive numbers from the rest of the list.
if (firstNeg.isEmpty) l else pos:::List(firstneg.head):::firstneg.tail.filter(_>=0)
//> res0: List[Int] = List(1, 2, -4, 5, 3)
(The List around firstneg.head is just for the symmetry of ::: both sides)
val l = List(1, 2, -4, 5, -6, -1, 3)
val (left, right) = l.span(_ > 0)
val result = right.headOption match {
case Some(n) => (left :+ n) ++ right.tail.filter(_ > 0)
case None => left
}
This is an obvious work for fold operation!
val l = List(1, 2, -4, 5, -6, -1, 3)
var result = l.foldLeft((true, Vector.empty[Int])) {
case ((f, r), x) if x >= 0 => (f, r :+ x)
case ((f, r), x) if f => (false, r :+ x)
case ((f, r), x) => (f, r)
}._2
println(result) // Vector(1, 2, -4, 5, 3)
I used a vector as an intermediate structure; you can convert it to a list with toList, if you need it. Or you can use it instead of the Vector, but you will have to reverse the addition order (r :+ x => x :: r) and then reverse the list in the end with reverse method.
If you want to maintain the order (i.e., the position of the negative), you could do something like this:
val list = List(1, 2, -4, 5, -6, -1, 3)
val negIndex = list.indexWhere(_ < 0)
val positive = list.zipWithIndex.filter { case (num, index) =>
num >= 0 || index == negIndex
}.map(_._1)
The negative requirement makes it hard to keep it more succinct than that. My strategy is to just grab the index of the first negative with indexWhere (will be -1 if there is none), then filter all the negatives out of the list, except for the index of the first negative. If the index was -1, no harm, no foul.
Here is tail recursive solution preserving order:
def posNeg(xs: List[Int]): List[Int] = {
#tailrec
def go(tail: List[Int], res: List[Int]): List[Int] = {
tail match {
case h :: t =>
if (h >= 0) go(t, h :: res)
else (h :: res).reverse ::: t.filter(_ > 0)
case _ => res
}
}
go(xs, Nil)
}
There are a lot of tail-recursive solutions, but they're all longer than they need to be.
def oneNeg(xs: List[Int]): List[Int] = {
def loop(in: List[Int], out: List[Int], neg: Int): List[Int] = in match {
case Nil => out
case x :: rest =>
if (neg < 0 && x < 0) loop(rest, out, neg)
else loop(rest, x :: out, x min neg)
}
loop(xs, Nil, 0).reverse
}
If this is not a public-facing API, you can make it shorter yet by just exposing the inner method alone:
def oneNeg(in: List[Int], out: List[Int] = Nil, neg: Int = 0): List[Int] =
in match {
case Nil => out.reverse
case x :: rest =>
if (neg < 0 && x < 0) oneNeg(rest, out, neg)
else oneNeg(rest, x :: out, x min neg)
}
Here is an improvement on the most concise answer I saw, by #sschaef in a comment:
val l = List(1, 2, -4, 5, -6, -1, 3)
l.span(_>=0) match { case (left, Nil) => left
case (left, x::right) => left ++ (x +: right.filter(_>=0)) }
You can try:
val list = List(1, 2, -4, 5, -6, -1, 3)
val index = list.indexWhere(_ < 0) + 1
list.take(index) ++ list.drop(index).filter(_ > 0)
Lets assume we have a Scala list:
val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
We can easily remove duplicates using the following code:
l1.distinct
or
l1.toSet.toList
But what if we want to remove duplicates only if there are more than 2 of them? So if there are more than 2 elements with the same value we remain only two and remove the rest of them.
I could achieve it with following code:
l1.groupBy(identity).mapValues(_.take(2)).values.toList.flatten
that gave me the result:
List(2, 2, 5, 1, 1, 3, 3)
Elements are removed but the order of remaining elements is different from how these elements appeared in the initial list. How to do this operation and remain the order from original list?
So the result for l1 should be:
List(1, 2, 3, 1, 3, 2, 5)
Not the most efficient.
scala> val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
l1: List[Int] = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
scala> l1.zipWithIndex.groupBy( _._1 ).map(_._2.take(2)).flatten.toList.sortBy(_._2).unzip._1
res10: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
My humble answer:
def distinctOrder[A](x:List[A]):List[A] = {
#scala.annotation.tailrec
def distinctOrderRec(list: List[A], covered: List[A]): List[A] = {
(list, covered) match {
case (Nil, _) => covered.reverse
case (lst, c) if c.count(_ == lst.head) >= 2 => distinctOrderRec(list.tail, covered)
case _ => distinctOrderRec(list.tail, list.head :: covered)
}
}
distinctOrderRec(x, Nil)
}
With the results:
scala> val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
l1: List[Int] = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
scala> distinctOrder(l1)
res1: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
On Edit: Right before I went to bed I came up with this!
l1.foldLeft(List[Int]())((total, next) => if (total.count(_ == next) >= 2) total else total :+ next)
With an answer of:
res9: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
Not the prettiest. I look forward to seeing the other solutions.
def noMoreThan(xs: List[Int], max: Int) =
{
def op(m: Map[Int, Int], a: Int) = {
m updated (a, m(a) + 1)
}
xs.scanLeft( Map[Int,Int]().withDefaultValue(0) ) (op).tail
.zip(xs)
.filter{ case (m, a) => m(a) <= max }
.map(_._2)
}
scala> noMoreThan(l1, 2)
res0: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
More straightforward version using foldLeft:
l1.foldLeft(List[Int]()){(acc, el) =>
if (acc.count(_ == el) >= 2) acc else el::acc}.reverse
Similar to how distinct is implemeted, with a multiset instead of a set:
def noMoreThan[T](list : List[T], max : Int) = {
val b = List.newBuilder[T]
val seen = collection.mutable.Map[T,Int]().withDefaultValue(0)
for (x <- list) {
if (seen(x) < max) {
b += x
seen(x) += 1
}
}
b.result()
}
Based on experquisite's answer, but using foldLeft:
def noMoreThanBis(xs: List[Int], max: Int) = {
val initialState: (Map[Int, Int], List[Int]) = (Map().withDefaultValue(0), Nil)
val (_, result) = xs.foldLeft(initialState) { case ((count, res), x) =>
if (count(x) >= max)
(count, res)
else
(count.updated(x, count(x) + 1), x :: res)
}
result.reverse
}
distinct is defined for SeqLike as
/** Builds a new $coll from this $coll without any duplicate elements.
* $willNotTerminateInf
*
* #return A new $coll which contains the first occurrence of every element of this $coll.
*/
def distinct: Repr = {
val b = newBuilder
val seen = mutable.HashSet[A]()
for (x <- this) {
if (!seen(x)) {
b += x
seen += x
}
}
b.result()
}
We can define our function in very similar fashion:
def distinct2[A](ls: List[A]): List[A] = {
val b = List.newBuilder[A]
val seen1 = mutable.HashSet[A]()
val seen2 = mutable.HashSet[A]()
for (x <- ls) {
if (!seen2(x)) {
b += x
if (!seen1(x)) {
seen1 += x
} else {
seen2 += x
}
}
}
b.result()
}
scala> distinct2(l1)
res4: List[Int] = List(1, 2, 3, 1, 3, 2, 5)
This version uses internal state, but is still pure. It is also quite easy to generalise for arbitrary n (currently 2), but specific version is more performant.
You can implement the same function with folds carrying the "what is seen once and twice" state with you. Yet the for loop and mutable state does the same job.
How about this:
list
.zipWithIndex
.groupBy(_._1)
.toSeq
.flatMap { _._2.take(2) }
.sortBy(_._2)
.map(_._1)
Its a bit ugly, but its relatively faster
val l1 = List(1, 2, 3, 1, 1, 3, 2, 5, 1)
l1.foldLeft((Map[Int, Int](), List[Int]())) { case ((m, ls), x) => {
val z = m + ((x, m.getOrElse(x, 0) + 1))
(z, if (z(x) <= 2) x :: ls else ls)
}}._2.reverse
Gives: List(1, 2, 3, 1, 3, 2, 5)
Here is a recursive solution (it will stack overflow for large lists):
def filterAfter[T](l: List[T], max: Int): List[T] = {
require(max > 1)
//keep the state of seen values
val seen = Map[T, Int]().withDefaultValue(0)//init to 0
def filterAfter(l: List[T], seen: Map[T, Int]): (List[T], Map[T, Int]) = {
l match {
case x :: xs =>
if (seen(x) < max) {
//Update the state and pass to next
val pair = filterAfter(xs, seen updated (x, seen(x) + 1))
(x::pair._1, pair._2)
} else {
//already seen more than max
filterAfter(xs, seen)
}
case _ => (l, seen)//empty, terminate recursion
}
}
//call inner recursive function
filterAfter(l, seen, 2)._1
}
Here is canonical Scala code to do reduce three or more in a row to two in a row:
def checkForTwo(candidate: List[Int]): List[Int] = {
candidate match {
case x :: y :: z :: tail if x == y && y == z =>
checkForTwo(y :: z :: tail)
case x :: tail =>
x :: checkForTwo(tail)
case Nil =>
Nil
}
}
It looks at the first three elements of the list, and if they are the same, drops the first one and repeats the process. Otherwise, it passes items on through.
Solution with groupBy and filter, without any sorting (so it's O(N), sorting will give you additional O(Nlog(N)) in typical case):
val li = l1.zipWithIndex
val pred = li.groupBy(_._1).flatMap(_._2.lift(1)) //1 is your "2", but - 1
for ((x, i) <- li if !pred.get(x).exists(_ < i)) yield x
I prefer approach with immutable Map:
def noMoreThan[T](list: List[T], max: Int): List[T] = {
def go(tail: List[T], freq: Map[T, Int]): List[T] = {
tail match {
case h :: t =>
if (freq(h) < max)
h :: go(t, freq + (h -> (freq(h) + 1)))
else go(t, freq)
case _ => Nil
}
}
go(list, Map[T, Int]().withDefaultValue(0))
}