Groupby Array[Array[String]] Scala - arrays

I have an Array[Array[String]] like this:
Array(Array("A","1","2"),
Array("A","3","4"),
Array("A","5","6"),
Array("B","7","8"),
Array("B","9","10"))
I would like to groupby on the first element of each sub Array and get a Map like this:
var A:Map[String, Array[String] = Map()
A + = ('A' -> Array("1", "2"))
A + = ('A' -> Array("3", "4"))
A + = ('A' -> Array("5", "6"))
A + = ('B' -> Array("7", "8"))
A + = ('B' -> Array("9", "10"))
I don't know how to manipulate groupby to get this result.
Do you have any idea?

Try this.
val arr = Array(Array("A","1","2"),
Array("A","3","4"),
Array("A","5","6"),
Array("B","7","8"),
Array("B","9","10"))
val result = arr.groupBy(_.head).map{case (k,v) => k -> v.flatMap(_.tail)}
result("A") // Array(1, 2, 3, 4, 5, 6)
result("B") // Array(7, 8, 9, 10)
Basically, after grouping you need to remove the head of each sub-array (that's the tail part), and you need to flatten the sub-arrays into a single array (that's the flatMap part).
Warning: this will throw a runtime exception if any of the sub-arrays are empty. Here's a version that will take care of that.
val result=arr.groupBy(_.headOption).collect{case (Some(k),v)=>k->v.flatMap(_.tail)}

Related

Comparing Arrays in Kotlin

I am learning kotlin at the moment. Is there a way to "compare" two arrays? For example
I have an array (1,2,3) and an array (1,2,1). The output should be something like this:
"2,2" for "took two from the indice two".
Thanks in advance.
You can use zip as follows:
val array1 = listOf(1, 2, 3)
val array2 = listOf(1, 2, 1)
val out1 = array1.zip(array2, Int::minus)
println(out1) // [0, 0, 2]
This gives you a new array with the values of the differences.
From there, it's just a short step to the (uncommon) format you're requesting using mapIndexedNotNull:
val out2 = out1.mapIndexedNotNull{ i, v -> if (v != 0) listOf(i, v) else null }
println(out2) // [[2, 2]]

Kotlin initialize an Array using another array

I can initialize an array in Kotlin like this:
val mArr = Array<Int>(5) {0}
and I'll have the following array [0,0,0,0,0]
The thing is, I need to initialise an array and put the values of another array into it.
i.e:
initialArray = [1, 4, 5 ,-2, 7]
val offset = 5
And should get mArr = [6, 9, 10, 3, 12]
Is there a way to set the value of each mArr[i] based on each initialArray[i]?
Something like
val mArr = Array<Int>(initialArray.size) { offset + initialArray[index]}
Without wrapping it in a for loop
There is map function for array.
So:
val initialArray = arrayOf(1, 4, 5 ,-2, 7)
val offset = 5
val newArray = initialArray.map { it + offset }.toTypedArray()
But this way you create new array without modifying the old one.
If you want modify old array you can use forEachIndexed extension method:
initialArray.forEachIndexed { index, value ->
initialArray[index] = initialArray[index] + offset
// or:
initialArray[index] = value + offset
}
val mArr = Array<Int>(initialArray.size) { offset + initialArray[index] }
already nearly works. It's just that index isn't defined here. You want it to be the function's parameter, so { index -> offset + initialArray[index] } or shorter { offset + initialArray[it] }. Also, for this you probably want IntArray instead of Array<Int> (and for initialArray as well). Combining these changes:
val mArr = IntArray(initialArray.size) { offset + initialArray[it] }

Finding common strings from map type and array Scala without loops

I am trying to find the common strings in a map and an array to output the respective values(from map, values here is Map[key -> value]) in Scala, I'm trying to not use any loops. Example:
Input:
Array("Ash","Garcia","Mac") Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3)
Output:
Array(5,4)
The output is an array with 5 and 4 because Ash and Mac are common in both the data structures
What constitutes a loop?
def common(arr: Array[String], m: Map[String,Int]): Array[Int] =
arr flatMap m.get
Usage:
common(Array("Ash","Garcia","Mac")
,Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3))
// res0: Array[Int] = Array(5, 4)
This is the most elegant solution, I think, but the results may not fit your requirements if there are duplicates in the array.
yourArray.collect(yourMap) // Array(5,4)
Use .filter to find the matching entries only, then get the value of your filtered map.
Given
scala> val names = Array("Ash","Garcia","Mac")
names: Array[String] = Array(Ash, Garcia, Mac)
scala> val nameToNumber = Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3)
nameToNumber: scala.collection.immutable.Map[String,Int] = Map(Ash -> 5, Mac -> 4, Lucas -> 3)
.filter.map
scala> nameToNumber.filter(x => names.contains(x._1)).map(_._2)
res3: scala.collection.immutable.Iterable[Int] = List(5, 4)
Alternatively, you can use collect,
scala> nameToNumber.collect{case kv if names.contains(kv._1) => kv._2}
res6: scala.collection.immutable.Iterable[Int] = List(5, 4)
Your complexity here is O(n2)
Quite easy for scala elegant syntax:
val a = Array("Ash","Garcia","Mac")
val m = Map("Ash" -> 5, "Mac" -> 4, "Lucas" -> 3)
println(m.filter { case (k, v) => a.contains(k)}.map { case (k, v) => v}.toArray)
Here is the solution!

Scala: iteration 2d array to do operation

A newbie here.
val arr_one = Array(Array(1, 2), Array(3, 4), Array(5, 6),Array(x, y)..and so on)
val arr_two = Array(Array(2,3), Array(4, 5), Array(6, 7))
var tempArr = ArrayBuffer[Double]()
I want to multiply arr_one and arr_two. for example
Iteration1 :Array(1*2+2*3, 1*4 +2*5, 1*6+2*7 ) assign to tempArr
Iteration2 :Array(3*2+4*3, 3*4 +4*5, 3*6+4*7) assign to tempArr
Iteration3 :Array(5*2+6*3, 5*4 +6*5, 5*6+6*7) assign to tempArr
I knew that if
val x = Array(1, 2) ; val y = Array(Array(2,3), Array(4, 5), Array(6, 7))
I can use y map {x zip _ map{case(a, b) => a * b} sum}
But If x like arr_one form, I don't know how to use for loop or something else to do that.
I really have on idea.
How can I do this in scala?
Really thanks.
I believe this does what you need, without any mutable state and "iterations" - it uses the "for-comprehension" syntax which is kind of a non-imperative for-loop - in other words, instead of changing state in each iteration, it returns a value which is the sequence of results per "iteration":
val result: Array[Array[Int]] = for (arr1 <- arr_one) yield {
for (arr2 <- arr_two) yield multArrays(arr1, arr2)
}
Assuming that multArrays has the following signature:
def multArrays(arr1: Array[Int], arr2: Array[Int]): Int
That calculates the value for each cell. A naive implementation (assuming arrays have size 2) would be:
def multArrays(arr1: Array[Int], arr2: Array[Int]): Int = {
arr1(0) * arr2(0) + arr1(1) * arr2(1)
}
But of course this can be generalized to any size arrays.
May be this is what you need:
val tmp = arr_one map ((arr1) => {arr_two map (arr2 => (arr1 zip arr2) map {case(a, b) => a * b} reduce (_ + _))} )
And to get ArrayBuffer simply use :
tmpArr = tmp.toBuffer

Multidimensional Array zip array in scala

I have two array like:
val one = Array(1, 2, 3, 4)
val two = Array(4, 5, 6, 7)
var three = one zip two map{case(a, b) => a * b}
It's ok.
But I have a multidimensional Array and a one-dimensional array now, like this:
val mulOne = Array(Array(1, 2, 3, 4),Array(5, 6, 7, 8),Array(9, 10, 11, 12))
val one_arr = Array(1, 2, 3, 4)
I would like to multiplication them, how can I do this in scala?
You could use:
val tmpArr = mulOne.map(_ zip one_arr).map(_.map{case(a,b) => a*b})
This would give you Array(Array(1*1, 2*2, 3*3, 4*4), Array(5*1, 6*2, 7*3, 8*4), Array(9*1, 10*2, 11*3, 12*4)).
Here mulOne.map(_ zip one_arr) maps each internal array of mulOne with corresponding element of one_arr to create pairs like: Array(Array((1,1), (2,2), (3,3), (4,4)), ..) (Note: I have used placeholder syntax). In the next step .map(_.map{case(a,b) => a*b}) multiplies each elements of pair to give
output like: Array(Array(1, 4, 9, 16),..)
Then you could use:
tmpArr.map(_.reduce(_ + _))
to get sum of all internal Arrays to get Array(30, 70, 110)
Try this
mulOne.map{x => (x, one_arr)}.map { case(one, two) => one zip two map{case(a, b) => a * b} }
mulOne.map{x => (x, one_arr)} => for every array inside mulOne, create a tuple with content of one_arr.
.map { case(one, two) => one zip two map{case(a, b) => a * b} } is basically the operation that you performed in your first example on every tuple that were created in the first step.
Using a for comprehension like this,
val prods =
for { xs <- mulOne
zx = one_arr zip xs
(a,b) <- zx
} yield a*b
and so
prods.sum
delivers the final result.

Resources