0

I'm trying to create a tuple from a scala list:

.map('path -> ('uri1, 'uri2, 'uri3, 'uri4, 'uri5)) {elems:List[String] =>

  (elems(0), elems(1), elems(2), elems(3), elems(4)) //ouf of bounds!
}

But the elems may have between 1 and 5 elements, so obviously I will hit an index out of bounds exception.

What's the scala/scalding way of doing this? I'm guessing that the proper way is to iterate a range from 1 to 5 and generate the tuple from there.

I'd like to return null (for compatibility reasons) when the elements do not exist.

Miguel Ping
  • 18,082
  • 23
  • 88
  • 136

3 Answers3

5

The approach here really depends on your requirements.

If you're after Tuple5 only when there are 5 elements defined in elem then a simple pattern match is a way to go (and as the function returns Option you can flatten it after map to get an expected result):

  def convert(l: List[String]): Option[(String, String, String, String, String)] = l match {
    case e1 :: e2 :: e3 :: e4 :: e5 :: _ => Some((e1, e2, e3, e4, e5))
    case _ => None
  }

Alternatively if you're after taking all the list sizes and converting them to Tuple5 with some default you can:

  • Use pattern matching as shown above and handle the remaining 5 cases (0,1,2,3,4 elems in the list) defaulting missing values.

  • Wrap your elem(n) calls with scala.util.Try and default (i.e. Try(elem(1)).getOrElse(""))

  • Add the default values to the elem list to fill in the missing values

Example illustrating last option below:

  def convert(l: List[String], default : String): (String, String, String, String, String) = {
    val defaults = (1 to 5 - l.size).map(_ => default).toList
    l ++ defaults match {
      case e1 :: e2 :: e3 :: e4 :: e5 :: _ => (e1, e2, e3, e4, e5)
    }
  }
Norbert Radyk
  • 2,608
  • 20
  • 24
1

There is a way to do this in 1 line, let stringList be the List[String] and default be some default

new Tuple(stringList.map(_.asInstanceOf[AnyRef]): _*) ++ (stringList.size until 5).map(_ => default)

Problem with this is it's not typesafe, so I gave Norbert an upvote because his answer is - and perhaps easier to read.

samthebest
  • 30,803
  • 25
  • 102
  • 142
1

You can pad the list with nulls as necessary:

.map('path -> ('uri1, 'uri2, 'uri3, 'uri4, 'uri5)) {elems:List[String] =>
  val padded= elems ++ List.fill(5)(null)
  (padded(0), padded(1), padded(2), padded(3), padded(4))  //No ouf of bounds!
}
Sasha O
  • 3,710
  • 2
  • 35
  • 45