How to achieve the below sequence? - scala

How to achieve result sequence with the given 2 sequences ?
val seq1 = Seq("A","B","C")
val seq2 = Seq(1,2,3)
val Result = Seq("A1","A2","A3","B1", "B2", "B3", "C1", "C2", "C3")

You can just use for comprehensions to find all combinations and concat the result into string:
val seq1 = Seq("A", "B", "C")
val seq2 = Seq(1, 2, 3)
val Result = for {
s1 <- seq1
s2 <- seq2
} yield s1 + s2

Related

How to combine four lists into a list of lists in Scala [duplicate]

This question already has answers here:
How to perform transpose on List of Lists in scala?
(2 answers)
Closed 2 years ago.
Let's say I have 4 fixed lists, all the same length:
val list1: List[String] = List("a", "1", "w")
val list2: List[String] = List("b", "2", "x")
val list3: List[String] = List("c", "3", "y")
val list4: List[String] = List("d", "4", "z")
I want to have them in a combined/composite list that returns:
List(List("a","b","c","d"), List("1","2","3","4"), List("w","x","y","z"))
I have tried using fold and flatMaps but I can't seem to understand fully how to implement this. If someone can also explain a good solution as well so that I can learn, I will greatly appreciate it.
Use transpose:
val list1 = List("a", "1", "w")
val list2 = List("b", "2", "x")
val list3 = List("c", "3", "y")
val list4 = List("d", "4", "z")
List(list1, list2, list3, list4).transpose
// List(List(a, b, c, d), List(1, 2, 3, 4), List(w, x, y, z))
Updated answer, after reading updated question carefully :)
val list1: List[String] = List("a", "1", "w")
val list2: List[String] = List("b", "2", "x")
val list3: List[String] = List("c", "3", "y")
val list4: List[String] = List("d", "4", "z")
val result = List(list1, list2, list3, list4)
.flatMap(_.zipWithIndex)
.groupBy{ case(value,index) => index}
.values
.toList
.map(_.map(_._1))
Also in your code, those should be List[String]

How to write nested for loops in efficient way in scala?

I am working on a scenario where I need to have nested for loops. I am able to get the desired output though but thought there might be some better way to achieve that too.
I am having the sample DF and wanted the output in the below format
List(/id=1/state=CA/, /id=2/state=MA/, /id=3/state=CT/)
Below snippet does the job but any suggestion improve it.
Example:
val stateDF = Seq(
(1, "CA"),
(2, "MA"),
(3, "CT")
).toDF("id", "state")
var cond = ""
val columnsLst =List("id","state")
var pathList = List.empty[String]
for (row <- stateDF.collect) {
cond ="/"
val dataRow = row.mkString(",").split(",")
for (colPosition <- columnsLst.indices) {
cond = cond + columnsLst(colPosition) + "=" + dataRow(colPosition) + "/"
}
pathList = pathList ::: List(cond)
}
println(pathList)
You can convert your dataframe to the format you want, and do a collect later if needed, here is the sample code:
scala> stateDF.select(concat(lit("/id="), col("id"),lit("/state="), col("state"), lit("/")).as("value")).show
+---------------+
| value|
+---------------+
|/id=1/state=CA/|
|/id=2/state=MA/|
|/id=3/state=CT/|
+---------------+
Thank you for all the sugestion. Now I come up the below for my above requirement.
import org.apache.spark.sql.{DataFrame}
val stateDF = Seq(
(1, "CA"),
(2, "MA"),
(3, "CT")
).toDF("id", "state")
val allStates = stateDF.columns.foldLeft(stateDF) {
(acc: DataFrame, colName: String) =>
acc.withColumn(colName, concat(lit("/" + colName + "="), col(colName)))
}
val dfResults = allStates.select(concat(allStates.columns.map(cols => col(cols)): _*))
val columnList: List[String] = dfResults.map(col => col.getString(0) + "/").collect.toList
println(columnList)

Scala - How to group elements by occurrence?

Is there a function in scala that groups all elements of a list by the number of these occurrences?
For example, I have this list:
val x = List("c", "b", "b", "c", "a", "d", "c")
And I want to get a new list like that:
x = List((3, "c"), (2, "b"), (1, "a"), (1, "d"))
You can first count the occurrences of each element and then reverse the resulting tuples:
List("c", "b", "b", "c", "a", "d", "c")
.groupBy(identity).mapValues(_.size) // Map(b -> 2, d -> 1, a -> 1, c -> 3)
.toList // List((b,2), (d,1), (a,1), (c,3))
.map{ case (k, v) => (v, k) } // List((2,b), (1,d), (1,a), (3,c))
You don't specifically mention a notion of order for the output, but if this was a requirement, this solution would need to be adapted.
Try this to get exactly what you want in the order you mentioned. (ie., order preserved in the List while taking counts):
x.distinct.map(v=>(x.filter(_==v).size,v))
In SCALA REPL:
scala> val x = List("c", "b", "b", "c", "a", "d", "c")
x: List[String] = List(c, b, b, c, a, d, c)
scala> x.distinct.map(v=>(x.filter(_==v).size,v))
res225: List[(Int, String)] = List((3,c), (2,b), (1,a), (1,d))
scala>

Find the sum of a list in Scala

If I have a list of strings and I know the numeric vlaue of each string in the list how do i get the sum of the list?
Example:
I know:
a = 1
b = 2
c = 3
d = 4
e = 5
I am given the following list:
List("a","b","d")
what the best way of calculating the sum 7?
Thanks
val a = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5)
val b = List("a", "b", "d")
b.map(a.getOrElse(_, 0)).sum
If you know that the values are the same as the element position, then you can avoid a map:
object test {
val list = List("a", "b", "c", "d", "e")
def sumThem = (for((letter, value) <- list.zipWithIndex) yield(value + 1)).sum
}
scala> test.sumThem
res2: Int = 15
If you're 100% sure it's only letters
List("a","b","d").foldLeft(0)(_ + _.hashCode - 96)
if not, you can map it before
val letters = (1 to 26).map(x => Character.toString((x+96).toChar) -> x).toMap
and use #sheunis's answer:
val input = List("a","b","d")
input.map(letters.getOrElse(_, 0)).sum

Can I yield or map one element into many in Scala?

val inArray = Array("a", "b", "c", "d")
// ...
val outArray = Array("a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3", "d1", "d2", "d3")
How to map inArray to outArray?
The idea is to iterate through inArray yielding 3 elements (by concatenating an index in this example) from each of its elements.
You can do that with flatMap.
inArray.flatMap(c => (1 to 3).map(c+))
This can look better using a for-comprehension
for {
s <- inArray
i <- Array(1, 2, 3) //or other traversable
}
yield s + i
This uses a combination of map and flatMap under the covers as described in detail in the SLS
Using for-comprehension.
scala> for {
| x <- Array("a", "b", "c", "d")
| n <- 1 to 3
| } yield x + n
res0: Array[java.lang.String] = Array(a1, a2, a3, b1, b2, b3, c1, c2, c3, d1, d2, d3)