-2

I have an array

val L = Array((1,Array("one", "two")), (2, Array("one", "three")))

I can do this manipulation

val LL = L.map({case (s,Array(s1,s2))=>(s1,s2,1)})

I want to do the same thing but with arrays of an indeterminate number of elements. For example : val L = Array((1,Array("one", "two", "three", "four")), (2, Array("one", "three"))). This is just an example so basically I want a code that works for any array regardless of how many elements it has.

EDIT : I think I found a simple way to do it. As an example :

val L = Array((1,Array("one", "two", "three")), (2, Array("one", "three")))
val LL = L.flatMap({case (s,contents)=>(contents.map(s=>(s,1)))})

Instead of (s1,s2) I just generalized it using the name contents then mapped the inner array contents inside a flatMap.

SidiAli
  • 139
  • 1
  • 2
  • 10

1 Answers1

0

Solution using Java reflection:

println(
  Array((1, Array("one", "two", "three", "four")), (2, Array("one", "three")))
    .map(_._2)
    .map(arr => {
      val arr1 = new Array[Object](arr.length + 1)
      Array.copy(arr, 0, arr1, 0, arr.length)
      arr1(arr.length) = 1.asInstanceOf[Object]
      arr1
    })
    .map(arrayToTuple)
    .deep
) 
// Array((one,two,three,four,1), (one,three,1))

def arrayToTuple[A <: Object](arr: Array[A]): Product = {
  val clazz = Class.forName("scala.Tuple" + arr.length)
  clazz.getConstructors.apply(0).newInstance(arr: _*).asInstanceOf[Product]
}

Based on answer.

Works only if length of inner arrays is <= 21.

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • Unfortunately the length of the inner arrays are always superior to 21. – SidiAli Oct 15 '17 at 12:15
  • @SidiAli Then how do you expect to have tuples? There are tuples from Tuple2 to Tuple22. You should formulate better what you expect to get. You can use nested tuples, HLists or case classes (if you use shapeless). – Dmytro Mitin Oct 15 '17 at 12:30
  • I found a way to do it using and flatMap and a Map in the same command. Cf edit. – SidiAli Oct 15 '17 at 14:20
  • @SidiAli The output is `Array((one,1), (two,1), (three,1), (one,1), (three,1))`. Only you can know if that's what you are after. – Dmytro Mitin Oct 15 '17 at 14:25
  • Yes that was my desired result from the beggining. I had to write another command when it was just for an array of 2 elements to group each element in a tuple with 1, so I could do a reduceByKey and count how many times a word occurs in the array. – SidiAli Oct 15 '17 at 14:38
  • 2
    @SidiAli Well, I'm glad you resolved your issue but I guess you should try to formulate your question better next time since it's different from what you wrote in comments: "For your example of Array((1,Array("one", "two", "three", "four")), what should the output be?" "The same as the first one so ("one", "two", "three", "four", 1)" – Dmytro Mitin Oct 15 '17 at 14:47