How to compare two integer array in Scala? - scala

Find a number available in first array with numbers in second. If number not found get the immediate lower.
val a = List(1,2,3,4,5,6,7,8,9)
val b = List(1,5,10)
expected output after comparing a with b
1 --> 1
2 --> 1
3 --> 1
4 --> 1
5 --> 5
6 --> 5
7 --> 5
8 --> 5
9 --> 5
Thanks

You can use TreeSet's to() and lastOption methods as follows:
val a = List(1, 2, 3, 4, 5, 6, 7, 8, 9)
val b = List(1, 5, 10)
import scala.collection.immutable.TreeSet
// Convert list `b` to TreeSet
val bs = TreeSet(b.toSeq: _*)
a.map( x => (x, bs.to(x).lastOption.getOrElse(Int.MinValue)) ).toMap
// res1: scala.collection.immutable.Map[Int,Int] = Map(
// 5 -> 5, 1 -> 1, 6 -> 5, 9 -> 5, 2 -> 1, 7 -> 5, 3 -> 1, 8 -> 5, 4 -> 1
// )
Note that neither list a or b needs to be ordered.
UPDATE:
Starting Scala 2.13, methods to for TreeSet is replaced with rangeTo.

Here is another approach using collect function
val a = List(1,2,3,4,5,6,7,8,9)
val b = List(1,5,10)
val result = a.collect{
case e if(b.filter(_<=e).size>0) => e -> b.filter(_<=e).reverse.head
}
//result: List[(Int, Int)] = List((1,1), (2,1), (3,1), (4,1), (5,5), (6,5), (7,5), (8,5), (9,5))
Here for every element in a check if there is a number in b i.e. which is greater than or equal to it and reverse the filter list and get its head to make it a pair.

Related

For loop to create tuples of adjacent elements

I have a array
[1,2,2,3,4,6,2,4,6,8,2,3,5]
I want to iterate over this array using a for loop to get a collection of tuples of adjacent elements. How should I code in Scala?
Expected output :
1-2|2-2|2-3|3-4|4-6|6-2|2-4|4-6|6-8|8-2|2-3|3-5
If you want the output like 1-2|2-2|2-3|3-4|........ as you mentioned in your comment you can try following,
val arr = Array(1,2,2,3,4,6,2,4,6,8,2,3,5)
//here first separate array elements by - then whole array by |
val str = arr.sliding(2).map(_.mkString("-")).mkString("|")
print(str)
//output
//1-2|2-2|2-3|3-4|4-6|6-2|2-4|4-6|6-8|8-2|2-3|3-5
In scala you have sliding function for that.
scala> val arr = Array(1,2,2,3,4,6,2,4,6,8,2,3,5)
arr: Array[Int] = Array(1, 2, 2, 3, 4, 6, 2, 4, 6, 8, 2, 3, 5)
scala> arr.sliding(2).foreach(tuple => println(tuple.mkString(" ")))
1 2
2 2
2 3
3 4
4 6
6 2
2 4
4 6
6 8
8 2
2 3
3 5
scala> arr.sliding(2).map(tuple => tuple.mkString("-")).mkString("|")
res10: String = 1-2|2-2|2-3|3-4|4-6|6-2|2-4|4-6|6-8|8-2|2-3|3-5

Spark Scala 26035582 Re-visited

Whilst I understand the ouctome here, I cannot see how the highlighted aspects work.
Please, enlighten me
def isHeavy(inp: String) = inp.split(",").map(weights(_)).sum > 12
val input = List("a,b,c,d", "b,c,e", "a,c,d", "e,g")
val splitSize = 10000 // specify some number of elements that fit in memory.
val numSplits = (input.size / splitSize) + 1 // has to be > 0.
val groups = sc.parallelize(input, numSplits) // specify the # of splits.
val weights = Array(("a", 3), ("b", 2), ("c", 5), ("d", 1), ("e", 9), ("f", 4), ("g", 6)).toMap
def isHeavy(inp: String) = inp.split(",").map(weights(_)).sum > 12
val result = groups.filter(isHeavy)
weights is a map keyed by strings
scala> weights
res13: scala.collection.immutable.Map[String,Int] = Map(e -> 9, f -> 4, a -> 3, b -> 2, g -> 6, c -> 5, d -> 1)
inp.split(",") will split the string, and the map function iterates over those keys, converting each into the value of the weights map for the respective key.
The underscore is a scala shortcut and can be written as such
inp.split(",").map(x => weights(x))
In other words, val input = List("a,b,c,d") becomes a list of numbers (3,2,5,1), which then get summed, and filtered out for those more than 12
For example,
scala> input.foreach(x => println(x.split(",").mkString))
abcd
bce
acd
eg
scala> input.foreach(x => println(x.split(",").map(weights(_)).mkString(",")))
3,2,5,1
2,5,9
3,5,1
9,6
scala> input.foreach(x => println(x.split(",").map(weights(_)).sum))
11
16
9
15
scala> input.foreach(x => {
| val sum = x.split(",").map(weights(_)).sum
| if (sum > 12) println(sum)
| })
16
15

Create 2D array and store value into each element of that array in Scala

I am working on a Scala exercise which asks me to create a 2D array of 4 rows and 5 columns and store the row index+column index+5 in each element. Also I have to sum the array by rows and then by columns and print the rows total and the columns total.I am so confused and I only know how to create an empty array.
val matrix = Array.ofDim[Int](4, 5)
Can you teach me how to do the rest of this exercise?
I will not tell you "the rest of the exercise" but I will try to show one way to create a 2D collection, like an array in this case:
val matrix1D = for {
rowIndex <- (0 until 4).toArray
colIndex <- (0 until 5).toArray
} yield rowIndex + colIndex + 5
Where
scala> :t matrix1D
Array[Int]
Now the result of this for-comprehension is the 1D version of your 2D array.
EDIT
I could probably give you few more hints:
scala> (0 to 11).toArray.grouped(4).toArray
res10: Array[Array[Int]] = Array(Array(0, 1, 2, 3), Array(4, 5, 6, 7), Array(8, 9, 10, 11))
scala> .transpose
res11: Array[Array[Int]] = Array(Array(0, 4, 8), Array(1, 5, 9), Array(2, 6, 10), Array(3, 7, 11))
EDIT
After you create matrix2D from matrix1D:
val matrix2D = matrix1D.??????????????????
Where
scala> :t matrix2D
Array[Array[Int]]
To print it out, you could simply use mkString:
scala> matrix2D.map(_.mkString("\t")).mkString("\n")
res32: String =
5 6 7 8 9
6 7 8 9 10
7 8 9 10 11
8 9 10 11 12

Make a tuple of three integers in Scala

I have a problem where I need to make a tuplet of three elements. Let's suppose that I have a list, and I managed to write tuplet of two elements:
val list = (1 to 10).toList
val map1 = list.foldLeft(Map.empty[Int,String])( (map, value) => map + (value -> value.toString) )
Map(5 -> 5, 10 -> 10, 1 -> 1, 6 -> 6, 9 -> 9, 2 -> 2, 7 -> 7, 3 -> 3, 8 -> 8, 4 -> 4)
I want to make a tuplet of three elements. How can I do that?
I tried this code:
val map1 = list.foldLeft(Map.empty[Int,String])( (map, value, s) => map + (value -> value.toString -> value.toString) )
Map(5 -> 5 -> 5, 10 -> 10-> 10, 1 -> 1-> 1, 6 -> 6-> 6, 9 -> 9-> 9, 2 -> 2-> 2, 7 -> 7-> 7, 3 -> 3-> 3, 8 -> 8-> 8, 4 -> 4-> 4)
-> is just a sugar notation for a pair (a tuple of two items). The universal notation for tuples of any arity is a comma-delimited list in braces. E.g. (1,2,3) is a tuple of three integers, while as in your example the expression 1 -> 2 -> 3 would desugar to ((1,2),3), which is a tuple of a tuple of two ints and an int.
What you're trying to achieve with your code simply doesn't make any sense. A Map can be constructed from a list of pairs, treating the first element of the tuple as a key and the second as a value. Tuples of any other arities are not supported and wouldn't make sense in that case. You can however construct collections of other types (e.g., a List) containing tuples of any arities.
In general to convert a range into a Tuple3 you could do something like this:
(0 to 10) map (x=>(x,x*2,x+10))
res0: scala.collection.immutable.IndexedSeq[(Int, Int, Int)] = Vector((0,0,10), (1,2,11), (2,4,12), (3,6,13), (4,8,14), (5,10,15), (6,12,16), (7,14,17), (8,16,18), (9,18,19), (10,20,20))
To join 2 Seqs as a Tuple2 you zip them:
(1 to 5) zip (10 to 15)
res3: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,10), (2,11), (3,12), (4,13), (5,14))
scala has built in support for zipping up to arity 3:
((0 to 3),(4 to 6),(7 to 9)).zipped.toList
res6: List[(Int, Int, Int)] = List((0,4,7), (1,5,8), (2,6,9))
If you need to do something similar to higher arities there's product-collections:
(0 to 3) flatZip (4 to 6) flatZip (7 to 9) flatZip (10 to 12)
res7: org.catch22.collections.immutable.CollSeq4[Int,Int,Int,Int] =
CollSeq((0,4,7,10),
(1,5,8,11),
(2,6,9,12))
And finally there's shapeless which does lots of cool things but has a moderate learning curve.

Scala stream behaves counterintuitive

I am playing with Scala's streams and I'm not sure I catch the idea.
Let's consider following code
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, fun(s.tail))
executing this
val f = fun(Stream.from(7))
f take 14 foreach println
results with
7 8 9 10 ... up to 20
Let's say I understand this.
Now, changing slightly code (adding 2 to head)
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head + 2, fun(s.tail))
results in
9 10 11 ... up to 22
Again I think I understand. Problems starts with next example (d
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head / 2, fun(s.tail))
3 4 4 5 5 6 6 7 7 8 8 9 9 10
This I do not get, please explain why it results this way?
Similar, subtracting also does not behave as I expect
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head - 2, fun(s.tail))
Output
5 6 7 8 9 10 ... up to 18
Given your "take": 7 8 9 10 ... up to 20,
what happens when you + 2 on each element?
what happens when you / 2 on each element (int arithmetic)?
what happens when you - 2 on each element?
Is it more intuitive if you think of it as mapping the Stream?
scala> val s1 = Stream.from(10)
s1: scala.collection.immutable.Stream[Int] = Stream(10, ?)
scala> val s2 = s1 map (_ * 2)
s2: scala.collection.immutable.Stream[Int] = Stream(20, ?)
scala> s2.take(5).toList
res0: List[Int] = List(20, 22, 24, 26, 28)
scala> val s3 = s1 map (_ / 2)
s3: scala.collection.immutable.Stream[Int] = Stream(5, ?)
scala> s3.take(5).toList
res1: List[Int] = List(5, 5, 6, 6, 7)
scala> val s4 = s1 map (_ - 2)
s4: scala.collection.immutable.Stream[Int] = Stream(8, ?)
scala> s4.take(5).toList
res2: List[Int] = List(8, 9, 10, 11, 12)
Ok, let's try and break it down...
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, fun(s.tail))
is a function that takes a Stream and separates its head and tail, applies itself recursively on the tail, and then recombines the two results with the cons operator.
Since the head is not touched during this operation, the Stream is rebuilt element by element as it was before.
val f = fun(Stream.from(7))
f it's the same as Stream.from(7) [i.e. an infinite sequence of increasing integers starting from 7]
Printing f take 14 in fact shows that we have the first 14 numbers starting from 7 [i.e. 7,8,9,...,20]
What happens next is that, while rebuilding the stream with the cons, each element is modified in some way
def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head + 2, fun(s.tail))
This adds 2 to the head before recombining it with the modified tail. The latter is modified in the same way, its first element being added to 2 and then recombined to its own tail, and so own.
If we assume again that s contains the number from 7 on, what happens looks like
fun(s) = cons(7 + 2, cons(8 + 2, cons(9 + 2, ... ad infinitum ... )))))
This is the same as adding 2 to each and every element of the stream s.
The code confirms that by printing "9 to 22", which is exactly "7 to 20" with 2 added to every element.
The others examples are analogous:
the stream with each element divided by 2 (and rounded to the floor
integer value, since the Stream is typed with Int values)
the stream where each element is decremented by 2