3

I have a peculiar case where I want to declare simple configuration like so

val config = List((("a", "b", "c"), ("first")), 
               (("d", "e"), ("second")),
               (("f"), ("third")))

which at run time, I would like to have a map, which maps like

"a" -> "first"
"b" -> "first"
"c" -> "first"
"d" -> "second"
"e" -> "second"
"f" -> "third"

Using toMap, I was able to convert the config to a Map

scala> config.toMap
res42: scala.collection.immutable.Map[java.io.Serializable,String] = Map((a,b,c) -> first, (d,e) -> second, f -> third)

But I am not able to figure out how to flatten the list of keys into keys so I get the final desirable form. How do I solve this?

2
  • 4
    That is not a simple configuration because you have tuples of different lengths inside each tuple (Note that the key type is java.io.Serializable). If you use Lists rather than tuples in the inner data it will be much easier. Commented Apr 27, 2020 at 7:07
  • You are right. Declaring the key as a list rather than tuples combined with the answer posted below, I was able to get my desired result. Thanks! Commented Apr 27, 2020 at 7:15

4 Answers 4

2

If you structure your config using List the code is very simple:

val config = List(
  (List("a", "b", "c"), ("first")),
  (List("d", "e"), ("second")),
  (List("f"), ("third")))

config.flatMap{ case (k, v) => k.map(_ -> v) }.toMap
Sign up to request clarification or add additional context in comments.

Comments

1

You can try the solution below:

val config = List(
      (("a", "b", "c"), ("first")),
      (("d", "e"), ("second")),
      (("f"), ("third")))

val result = config.map {
  case (k,v) =>
    (
      k.toString().replace(")", "")
        .replace("(", "")
        .split(","), v)
  }

val res = result.map {
  case (key,value) => key.map{ data =>
    (data,value)
  }.toList
}.flatten.toMap

In case you change the config structure to something like below, solution is much more simpler:

val config1 = List (
  (List("a", "b", "c"), "first"),
  (List("d", "e"), "second"),
  (List("f"), "third")
)


config1.flatMap{
  case (k,v) => k.map{data => (data,v)}
}.toMap

1 Comment

In your second example, here: case (k,v) => k.map{data => (data,v)}.toMap, toMap doesn't actually change anything. You can safely remove that and save some cpu cycles.
1

I think the above answers are good practical answers. If you're in a situation where you have no control over the input and you're stuck with Tuples instead of Lists, I'd do it this way:

val result: Map[String, String] = config.flatMap { 
  case (s: String, v) => List(s -> v)
  case (ks: Product, v) => ks.productIterator.collect { case s: String => s -> v }
  case _ => Nil //Prevent throwing
}.toMap

This will throw away anything that's not a String in the keys.

Comments

0

by using in built spark sql functions

val config = List((Array("a", "b", "c"), ("first")),
      (Array("d", "e"), ("second")),
      (Array("f"), ("third"))).toDF(List("col1","col2") : _*)

config.withColumn("exploded",functions.explode_outer($"col1")).drop("col1").show()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.