Scala: subtract index of odd values - scala

For a practical exercise I need to define a function that basically changes the index of every value in an odd index in a list, so that I would get this:
changePairs(List(1,2,3,4,5,6,7,8,9,10,11))
//> res62: List[Int] = List(2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 11)
changePairs(List(2,2,30,4,50,6,7,80,9,100))
//> res63: List[Int] = List(2, 2, 4, 30, 6, 50, 80, 7, 100, 9)
So basically I need to swap the places of each odd-even pair, and in case I'm left with a single odd element at the last index (11 in the first example), I leave it as it is.
I have this but it's definitely not working, and I'm not really sure why.
def changePairs(a: List[Int]) = a.zipWithIndex.map {
case (s,i) => if (i % 2 != 0) a.patch(i,Seq(s),1); a.patch(i-2,Seq(s),0);
}

Here's one way:
def changePairs(a: List[Int]) = a.grouped(2).flatMap {
case List(a, b) => List(b, a)
case a => a
}.toList
changePairs(List(1, 2, 3, 4, 5, 6, 7)) // List(2, 1, 4, 3, 6, 5, 7)
Main idea that gets you going is once you think of grouping the list into sublists of two elements, which is what grouped(2) does. From then on it's an easy ride - describe two cases, one with two elements (in that case we flip them) and one with only one element, such as 7 in my example, in which case we just leave it be. We use flatMap to flatten the resulting list of 2-element lists into one big list, and we do .toList to get out of an iterator that we got from grouped.
EDIT:
I now saw a.grouped(2).map(_.reverse).flatten.toList in the comments. Yeah, that works too, it's the same as this but much less verbose since instead of "manually" swapping the elements, we just do a reverse on each sublist.

You could also use recursion and pattern matching. This is efficient as you are only going through the list once:
def changePairs(l: List[Int]): List[Int] = {
l match {
case a :: b :: tail => b :: a :: changePairs(tail)
case _ => Nil
}
}

Related

How to remove duplicates from list without using in inbuilt libraries such as distinct, groupBy(identity), toSet.. Etc

I wanted to write a Scala program that takes command-line args as list input and provide the output list without duplicates.
I want to know the custom implementation of this without using any libraries.
Input : 4 3 7 2 8 4 2 7 3
Output :4 3 7 2 8
val x= List(4, 3, 7, 2, 8, 4, 2, 7, 3)
x.foldLeft(List[Int]())((l,v)=> if (l.contains(v)) l else v :: l)
if you can't use contains you can do another fold
x.foldLeft(List[Int]())((l,v)=> if (l.foldLeft(false)((contains,c)=>if (c==v ) contains | true else contains | false)) l else v :: l)
Here's a way you could do this using recursion. I've tried to lay it out in a way that's easiest to explain:
import scala.annotation.tailrec
#tailrec
def getIndividuals(in: List[Int], out: List[Int] = List.empty): List[Int] = {
if(in.isEmpty) out
else if(!out.contains(in.head)) getIndividuals(in.tail, out :+ in.head)
else getIndividuals(in.tail, out)
}
val list = List(1, 2, 3, 4, 5, 4, 3, 5, 6, 0, 7)
val list2 = List(1)
val list3 = List()
val list4 = List(3, 3, 3, 3)
getIndividuals(list) // List(1, 2, 3, 4, 5, 6, 0, 7)
getIndividuals(list2) // List(1)
getIndividuals(list3) // List()
getIndividuals(list4) // List(3)
This function takes two parameters, in and out, and iterates through every element in the in List until it's empty (by calling itself with the tail of in). Once in is empty, the function outputs the out List.
If the out List doesn't contain the value of in you are currently looking at, the function calls itself with the tail of in and with that value of in added on to the end of the out List.
If out does contain the value of in you are currently looking at, it just calls itself with the tail of in and the current out List.
Note: This is an alternative to the fold method that Arnon proposed. I personally would write a function like mine and then maybe refactor it into a fold function if necessary. I don't naturally think in a functional, fold-y way so laying it out like this helps me picture what's going on as I'm trying to work out the logic.

Scala - Scanleft, returning values within iterations without using it in a next turn

I have a list
what I would like to do is
def someRandomMethod(...): ... = {
val list = List(1, 2, 3, 4, 5)
if(list.isEmpty) return list
list.differentScanLeft(list.head)((a, b) => {
a * b
})
}
which returns
List(1, 2, 6, 12, 20) rather than List(1, 2, 6, 24, 120)
Is there such API?
Thank you,
Cosmir
scan is not really the right method for this, you want to use sliding to generate a list of adjacent pairs of values:
(1::list).sliding(2).map(l => l(0)*l(1))
More generally, it is sometimes necessary to pass data on to the next iteration when using scan. The standard solution to this is to use a tuple (state, ans) and then filter out the state with another map at the end.
You probably want to use zip
val list = List(1,2,3,4,5,6)
val result = list.zip(list.drop(1)).map{case (a,b) => a*b}
println(result)
> List(2, 6, 12, 20, 30)

Zip two Arrays, always 3 elements of the first array then 2 elements of the second

I've manually built a method that takes 2 arrays and combines them to 1 like this:
a0,a1,a2,b0,b1,a3,a4,a5,b2,b3,a6,...
So I always take 3 elements of the first array, then 2 of the second one.
As I said, I built that function manually.
Now I guess I could make this a one-liner instead with the help of zip. The problem is, that zip alone is not enough as zip builds tuples like (a0, b0).
Of course I can flatMap this, but still not what I want:
val zippedArray: List[Float] = data1.zip(data2).toList.flatMap(t => List(t._1, t._2))
That way I'd get a List(a0, b0, a1, b1,...), still not what I want.
(I'd then use toArray for the list... it's more convenient to work with a List right now)
I thought about using take and drop but they return new data-structures instead of modifying the old one, so not really what I want.
As you can imagine, I'm not really into functional programming (yet). I do use it and I see huge benefits, but some things are so different to what I'm used to.
Consider grouping array a by 3, and array b by 2, namely
val a = Array(1,2,3,4,5,6)
val b = Array(11,22,33,44)
val g = (a.grouped(3) zip b.grouped(2)).toArray
Array((Array(1, 2, 3),Array(11, 22)), (Array(4, 5, 6),Array(33, 44)))
Then
g.flatMap { case (x,y) => x ++ y }
Array(1, 2, 3, 11, 22, 4, 5, 6, 33, 44)
Very similar answer to #elm but I wanted to show that you can use more lazy approach (iterator) to avoid creating temp structures:
scala> val a = List(1,2,3,4,5,6)
a: List[Int] = List(1, 2, 3, 4, 5, 6)
scala> val b = List(11,22,33,44)
b: List[Int] = List(11, 22, 33, 44)
scala> val groupped = a.sliding(3, 3) zip b.sliding(2, 2)
groupped: Iterator[(List[Int], List[Int])] = non-empty iterator
scala> val result = groupped.flatMap { case (a, b) => a ::: b }
result: Iterator[Int] = non-empty iterator
scala> result.toList
res0: List[Int] = List(1, 2, 3, 11, 22, 4, 5, 6, 33, 44)
Note that it stays an iterator all the way until we materialize it with toList

Reverse list of n elements

i was given this problem and i thought I had it figured out , but i was told i had it wrong. the question was,. Given a list xs, reverse the first n elements. I guess im not understanding what the question was asking , i thought we take an Int n , and return the first n elements in front of that int n in reverse.
def nthRev[T](n: Int,xs: List[T]): List[T] = xs match {
case List() => List()
case head :: rest => (head::rest.take(n)).reverse
}
so, the output is
nthRev(3,List(1, 2, 3, 4, 5))
returns
List(4, 3, 2, 1)
but apparently its wrong, can anyone explain what the question is asking for?
The way I interpret your question "Given a list xs, reverse the first n elements." and the example
nthRev(3,List(1, 2, 3, 4, 5))
I would expect it to reverse the first 3 elements, but then leave the rest of the list:
List(3, 2, 1, 4, 5)
When the question says "first n elements" it is saying to replace "n" with the number given as the first argument in your example "3", to give "first 3 elements". The 3 has nothing to do with the element in the list. Changing your example:
nthRev(3,List(10,11,12,13,14)
would return
List(12,11,10,13,14)
I think it means you're supposed to return a new list that has the same elements of the original list, but with the first n elements reversed.
def nthRev[T](n: Int, xs: List[T]): List[T] =
xs.splitAt(n) match { case (a, b) => a.reverse ::: b }
nthRev(3, (1 to 5).toList) // List(3, 2, 1, 4, 5)
I would go with simple standard API. Have a look at the drop function explained in this post: Skip first N elements in scala iterable
def reverseAtN[a](n: Int, list: List[a]): List[a] =
List.concat(x.take(n).reverse, x.drop(n))

Filter condition using filtered value

I would like to filter collection, so distance between adjacent elements would be at least 5.
So List(1, 2, 3, 4, 5, 6, 7, 11, 20) will become List(1, 6, 11, 20).
Is it possible to achieve in one pass using filter? What would be scala-way?
How about this one-liner:
scala> l.foldLeft(Vector(l.head)) { (acc, item) => if (item - acc.last >= 5) acc :+ item else acc }
res7: scala.collection.immutable.Vector[Int] = Vector(1, 6, 11, 20)
Try with foldLeft():
val input = List(1, 2, 3, 4, 5, 6, 7, 11, 20)
input.tail.foldLeft(List(input.head))((out, cur) =>
if(cur - out.head >= 5) cur :: out else out
).reverse
If it's not obvious:
Algorithm starts with first element (probably you need some edge cases handled) in the output collection
It iterates over all remaining elements from the input. If the difference between this element (cur) and first element of input is greater than or equal than 5, prepend to input. Otherwise skip and proceed
input was built by prepending and examining head to get better performance. .reverse is needed in the end
This is basically how you would implement this in imperative way, but with more concise syntax.