Add list values after comparison and condition check - Scala - scala

I have three lists inside a list.
val l = List(List(1, 0, 0), List(1, 1, 0), List(1, 0, 1))
Now the problem is to add the values inside list with condition check, basically I need to check each element wise values and if they are equal do some calculation if not do another calculation. I tired to group same element positions using transpose, then map the result and make comparison of current element with previous element in the list, I think the last part is where I am not clear.
EDIT:
Some more explanation, let say we have list like this
List(List(i1, j1, k1), List(i2, j2, k2), List(in, jn, kn))
if i1 is equal to i2 then 1+i1+ i2*0.5 and j1 equal to j2 then 1+j1+j2*.0.5 and it goes upto kn
and the second condition is if they are not equal
i1 is not equal to i2 then it is a decrease, it will be i1+i2*0.5
hope this is explanation helps
Output I looking for
List[Double] = List(2.5, 0.5, 0.5)

Your description is still very confusing but I think maybe something like this is what you're after.
val lst = List(List(1, 0, 0), List(1, 1, 0), List(1, 0, 1))
lst.transpose
.map(sublst => sublst.sum*0.5 + (if (sublst.forall(_==sublst.head)) 1 else 0))
//res0: List[Double] = List(2.5, 0.5, 0.5)
If all the elements of the sub-list are the same, add 1 to the calculation, else add 0.

lst.transpose.map(v=>if(v.forall(_==v.head)) v.sum*0.5+1 else v.sum*0.5))
or
lst.transpose.map(v=>if(v.exists(_!=v.head)) v.sum*0.5 else v.sum*0.5+1)
or
lst.transpose.map(v=>if(v.find(_!=v.head)!=None) v.sum*0.5 else v.sum*0.5+1)
These are in general, can be used for two different expressions to be evaluated for the two different cases ie., all elements equal or not equal in the lists after calling transpose function.ie.,
lst.transpose.map(v=>if(v.exists(_!=v.head))
(Expression1 in terms of elements in v)
else (Expression2 in terms of elements in v) )
In Scala REPL:
for,
val lst = List(List(1, 0, 0), List(1, 1, 0), List(1, 0, 1))
scala> lst.transpose.map(v=>if(v.forall(_==v.head)) v.sum*0.5+1 else v.sum*0.5)
res23: List[Double] = List(2.5, 0.5, 0.5)
scala> lst.transpose.map(v=>if(v.exists(_!=v.head)) v.sum*0.5 else v.sum*0.5+1)
res24: List[Double] = List(2.5, 0.5, 0.5)
scala> lst.transpose.map(v=>if(v.find(_!=v.head)!=None) v.sum*0.5 else v.sum*0.5+1)
res25: List[Double] = List(2.5, 0.5, 0.5)

You can use map and pattern matching
val list = List(List(1, 0, 0), List(1, 1, 0), List(1, 0, 1))
val result = list.transpose.map {
case sublist if sublist.forall(sublist.head == _) => 1+0.5*sublist.sum
case sublist => 0.5*sublist.sum
}

Related

How to generate all permutations of splitting an array to two subarrays in Scala?

Given an array, I would like to split it into two non-empty subarrays.
For example, given the following array:
val nums = Array(1, 2, 3, 4)
I would like to generate the following unique permutations:
(Array(1), Array(2, 3, 4))
(Array(2), Array(1, 3, 4))
(Array(1, 2), Array(3, 4))
(Array(3), Array(1, 2, 4))
(Array(1, 3), Array(2, 4))
(Array(2, 3), Array(1, 4))
(Array(1, 2, 3), Array(4))
The permutations are unique in the sense that if a given split is just a mirror of another split, I only need to keep one of them. Also, the order of elements in the subarrays do not matter.
See below for a working solution: https://stackoverflow.com/a/57262577/5767875.
But I believe a more elegant and functional solution exists.
def splits(xs: Array[Int]): Array[(Array[Int], Array[Int])] = {
val startSplit: Array[(Array[Int], Array[Int])] = Array((Array(xs.head), Array.empty))
xs.tail.foldLeft(startSplit) { (splits, x) =>
splits.flatMap {
case (left, right) => Array((x +: left, right), (left, x +: right))
}
}.tail
}
The basic idea is that if you know all of the splits for the first N elements, then there are twice as many splits for N+1 elements: you can add the new element to either the left or the right for every split and obtain a new split. That's what's happening in the foldLeft call.
The only small wrinkles are: this would generate "mirror" splits, so the starting point just always has the first element on the left. And: at the end you have one extra output which is every element on the left, so the final call to .tail gets rid of that.
Note that the performance of this is probably pretty horrible, since scala arrays don't have efficient appends and such so every operation makes a copy. You could replace Array with List in the above code and get something better. If you really need to deal with arrays you could then just convert (.toList / .toArray)
Based on this SO post, below is a version of Scala code:
import scala.collection.mutable.ArrayBuffer
def generateSplitPermutations(nums: Array[Int]): Array[(Array[Int], Array[Int])] = {
var results: List[(Array[Int], Array[Int])] = List()
var flags = Array.fill(nums.length)(false)
var done = false
while (!done) {
var a = ArrayBuffer[Int]()
var b = ArrayBuffer[Int]()
for ((bool, i) <- flags.zipWithIndex) {
if (bool)
a += nums(i)
else
b += nums(i)
}
if (a.length > 0 && b.length > 0) {
results = results :+ (a.toArray, b.toArray)
}
if (flags.map(x => if (x) 1 else 0).sum == nums.length / 2 + 1) {
done = true
}
// if done is true, the following code block won't matter
var ok = false
for (i <- 0 until nums.length if !ok) {
flags(i) = !flags(i)
if (flags(i))
ok = true
}
}
results.toArray
}
val nums = Array(1, 2, 3, 4)
generateSplitPermutations(nums)
outputs:
scala> generateSplitPermutations(nums)
res16: Array[(Array[Int], Array[Int])] = Array((Array(1),Array(2, 3, 4)), (Array(2),Array(1, 3, 4)), (Array(1, 2),Array(3, 4)), (Array(3),Array(1, 2, 4)), (Array(1, 3),Array(2, 4)), (Array(2, 3),Array(1, 4)), (Array(1, 2, 3),Array(4)))
Is there a more Scala/functional way of achieving this?

if condition for partial argument in map

I understand how to use if in map. For example, val result = list.map(x => if (x % 2 == 0) x * 2 else x / 2).
However, I want to use if for only part of the arguments.
val inputColumns = List(
List(1, 2, 3, 4, 5, 6), // first "column"
List(4, 6, 5, 7, 12, 15) // second "column"
)
inputColumns.zipWithIndex.map{ case (col, idx) => if (idx == 0) col * 2 else col / 10}
<console>:1: error: ';' expected but integer literal found.
inputColumns.zipWithIndex
res4: List[(List[Int], Int)] = List((List(1, 2, 3, 4, 5, 6),0), (List(4, 6, 5, 7, 12, 15),1))
I have searched the error info but have not found a solution.
Why my code is not 'legal' in Scala? Is there a better way to write it? Basically, I want to do a pattern matching and then do something on other arguments.
To explain your problem another way, inputColumns has type List[List[Int]]. You can verify this in the Scala REPL:
$ scala
Welcome to Scala 2.12.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.
scala> val inputColumns = List(
| List(1, 2, 3, 4, 5, 6), // first "column"
| List(4, 6, 5, 7, 12, 15) // second "column"
| )
inputColumns: List[List[Int]] = List(List(1, 2, 3, 4, 5, 6), List(4, 6, 5, 7, 12, 15))
Now, when you call .zipWithIndex on that list, you end up with a List[(List[Int], Int)] - that is, a list of a tuple, in which the first tuple type is a List[Int] (the column) and the second is an Int (the index):
scala> inputColumns.zipWithIndex
res0: List[(List[Int], Int)] = List((List(1, 2, 3, 4, 5, 6),0), (List(4, 6, 5, 7, 12, 15),1))
Consequently, when you try to apply a map function to this list, col is a List[Int] and not an Int, and so col * 2 makes no sense - you're multiplying a List[Int] by 2. You then also try to divide the list by 10, obviously.
scala> inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
<console>:13: error: value * is not a member of List[Int]
inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
^
<console>:13: error: value / is not a member of List[Int]
inputColumns.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
^
In order to resolve this, it depends what you're trying to achieve. If you want a single list of integers, and then zip those so that each value has an associated index, you should call flatten on inputColumns before calling zipWithIndex. This will result in List[(Int, Int)], where the first value in the tuple is the column value, and the second is the index. Your map function will then work correctly without modification:
scala> inputColumns.flatten.zipWithIndex.map{ case(col, idx) => if(idx == 0) col * 2 else col / 10 }
res3: List[Int] = List(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1)
Of course, you no longer have separate columns.
If you wish each value in each list to have an associated index, you need to firstly map inputColumns into two zipped lists, using inputColumns.map(_.zipWithIndex) to create a List[List[(Int, Int)]] - a list of a list of (Int, Int) tuples:
scala> inputColumns.map(_.zipWithIndex)
res4: List[List[(Int, Int)]] = List(List((1,0), (2,1), (3,2), (4,3), (5,4), (6,5)), List((4,0), (6,1), (5,2), (7,3), (12,4), (15,5)))
We can now apply your original map function to the result of the zipWithIndex operation:
scala> inputColumns.map(_.zipWithIndex.map { case (col, idx) => if(idx == 0) col * 2 else col / 10 })
res5: List[List[Int]] = List(List(2, 0, 0, 0, 0, 0), List(8, 0, 0, 0, 1, 1))
The result is another List[List[Int]] with each internal list being the results of your map operation on the original two input columns.
On the other hand, if idx is meant to be the index of the column, and not of each value, and you want to multiply all of the values in the first column by 2 and divide all of the values in the other columns by 10, then you need to change your original map function to map across each column, as follows:
scala> inputColumns.zipWithIndex.map {
| case (col, idx) => {
| if(idx == 0) col.map(_ * 2) // Multiply values in first column by 1
| else col.map(_ / 10) // Divide values in all other columns by 10
| }
| }
res5: List[List[Int]] = List(List(2, 4, 6, 8, 10, 12), List(0, 0, 0, 0, 1, 1))
Let me know if you require any further clarification...
UPDATE:
The use of case in map is a common Scala shorthand. If a higher-order function takes a single argument, something such as this:
def someHOF[A, B](x: A => B) = //...
and you call that function like this (with what Scala terms a partial function - a function consisting solely of a list of case statements):
someHOF {
case expr1 => //...
case expr2 => //...
...
}
then Scala treats it as a kind-of shorthand for:
someHOF {a =>
a match {
case expr1 => //...
case expr2 => //...
...
}
}
or, being slightly more terse,
someHOF {
_ match {
case expr1 => //...
case expr2 => //...
...
}
}
For a List, for example, you can use it with functions such as map, flatMap, filter, etc.
In the case of your map function, the sole argument is a tuple, and the sole case statement acts to break open the tuple and expose its contents. That is:
val l = List((1, 2), (3, 4), (5, 6))
l.map { case(a, b) => println(s"First is $a, second is $b") }
is equivalent to:
l.map {x =>
x match {
case (a, b) => println(s"First is $a, second is $b")
}
}
and both will output:
First is 1, second is 2
First is 3, second is 4
First is 5, second is 6
Note: This latter is a bit of a dumb example, since map is supposed to map (i.e. change) the values in the list into new values in a new list. If all you were doing was printing the values, this would be better:
val l = List((1, 2), (3, 4), (5, 6))
l.foreach { case(a, b) => println(s"First is $a, second is $b") }
You are trying to multiply a list by 2 when you do col * 2 as col is List(1, 2, 3, 4, 5, 6) when idx is 0, which is not possible and similar is the case with else part col / 10
If you are trying to multiply the elements of first list by 2 and devide the elements of rest of the list by 10 then you should be doing the following
inputColumns.zipWithIndex.map{ case (col, idx) => if (idx == 0) col.map(_*2) else col.map(_/10)}
Even better approach would be to use match case
inputColumns.zipWithIndex.map(x => x._2 match {
case 0 => x._1.map(_*2)
case _ => x._1.map(_/10)
})

Scala get next index in the list from current item

Say for example I am mapping one list to the next, and in the map I want to do some calculation with the current item in the list with the next item in the list.
def someFunc(L: List[Integer]) : List[Integer] = {
L.collect {
case k if (k != L(L.length-1)) //do something with k and the next element
}
}
A simple example is I want to go through this List of Integers, and map each number onto the next number in the list divided by it.
E.g. (1,2,3) -> (2/1, 3/2) == (2, 1.5)
I had thought about doing this using indexOf but I don't think that is efficient having to search the whole list for the current element even though I am already traversing each element in the list anyway.
Use .sliding for this:
scala> val l = List(1, 2, 3)
l: List[Int] = List(1, 2, 3)
scala> l.sliding(2).toList
res0: List[List[Int]] = List(List(1, 2), List(2, 3))
scala> l.sliding(2).collect { case x::y::Nil if y != 0 => x / y.toDouble }.toList
res1: List[Double] = List(0.5, 0.6666666666666666)

Compare two list and get the index of same elements

val a = List(1,1,1,0,0,2)
val b = List(1,0,3,2)
I want to get the List of indices of elements of "List b" which are existing in "List a".
Here output to be List(0,1,3)
I tried this
for(x <- a.filter(b.contains(_))) yield a.indexOf(x))
Sorry. I missed this. The list size may vary. Edited the Lists
Is there a better way to do this?
If you want a result of indices, it's often useful to start with indices.
b.indices.filter(a contains b(_))
REPL tested.
scala> val a = List(1,1,1,0,0,2)
a: List[Int] = List(1, 1, 1, 0, 0, 2)
scala> val b = List(1,0,3,2)
b: List[Int] = List(1, 0, 3, 2)
scala> b.indices.filter(a contains b(_))
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 3)
val result = (a zip b).zipWithIndex.flatMap {
case ((aItem, bItem), index) => if(aItem == bItem) Option(index) else None
}
a zip b will return all elements from a that have a matching pair in b.
For example, if a is longer, like in your example, the result would be List((1,1),(1,0),(1,3),(0,2)) (the list will be b.length long).
Then you need the index also, that's zipWithIndex.
Since you only want the indexes, you return an Option[Int] and flatten it.
You can use indexed for for this:
for{ i <- 0 to b.length-1
if (a contains b(i))
} yield i
scala> for(x <- b.indices.filter(a contains b(_))) yield x;
res27: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 3)
Here is another option:
scala> val a = List(1,1,1,0,0,2)
a: List[Int] = List(1, 1, 1, 0, 0, 2)
scala> val b = List(1,0,3,2)
b: List[Int] = List(1, 0, 3, 2)
scala> b.zipWithIndex.filter(x => a.contains(x._1)).map(x => x._2)
res7: List[Int] = List(0, 1, 3)
I also want to point out that your original idea of: Finding elements in b that are in a and then getting indices of those elements would not work, unless all elements in b contained in a are unique, indexOf returns index of the first element. Just heads up.

Create and Append list based on other list member in Scala

I have list of Integer like this:
val aRowcol: List[List[Int]]] =
List(List(0, 0), List(0, 1), List(0, 2)),
List(List(1, 0), List(1, 1), List(1, 2)),
List(List(2, 0), List(2, 1), List(2, 2)),
List(List(0, 0), List(1, 1), List(2, 2)),
List(List(2, 0), List(1, 1), List(0, 2)),
List(List(1, 0), List(0, 1), List(0, 2)),
List(List(1, 0), List(2, 1), List(2, 2))
val aAlpha: List[List[String]] = List(
List("a","b","c","d"),
List("e","f","g","h"),
List("i","j","k","l","m"))
val i = 4
val resNum:List[List[Int,String]] = (0 to i) {
_map => List(
aRowcol.take(i).head.head,
aRowcol.take(i).head(1),
aAlpha(aRowcol.take(i).head.head)(aRowcol.take(i).head(1))}
.toList
But the result I want for val resNum is:
List(
List(0,0,"a"),
List(1,0,"e"),
List(2,0,"i"),
List(0,0,"a"),
List(2,0,"i"))
(0,0) means first row first column, we have "a" on that possition, so i will define how many aAlpha we will have. I think it will be much easier if we do i++, but you know that we couldn't do i++ in scala.
I'm guessing that you want to treat the first element in each "list of lists" in aRowcol as the "coordinates" of a letter in aAlpha, and want to append that letter to each of these "first elements".
If so:
val result: List[List[Any]] = aRowcol.take(5) // only 5 first rows
.map(_.head) // first List(i, j) only, the rest is ignored
.map { case List(i, j) => List(i, j, aAlpha(i)(j)) } // append the right letter to list
result.foreach(println)
// List(0, 0, a)
// List(1, 0, e)
// List(2, 0, i)
// List(0, 0, a)
// List(2, 0, i)
If that's not what you meant - please clarify.
EDIT: as for your version - it can work (and achieve the same goal) with a few fixes:
list.take(i) doesn't return the i-th element, it returns a list with the first i elements, I think you're trying to use list.apply(i) which returns the i-th element, or it's shorthand version: list(i)
If you want to map the numbers 0..4 - call map and then name the argument of the anonymous function you pass i - don't use a var declared outside of the method and expect it to increment
With these corrections (and some more), your version becomes:
val resNum: List[List[Any]] = (0 to 4).map { i =>
List(
aRowcol(i).head.head,
aRowcol(i).head(1),
aAlpha(aRowcol(i).head.head)(aRowcol(i).head(1))) }
.toList
Which works as you expect; But above is a similar yet simpler version.