Miguel Ping
Miguel Ping

Reputation: 18347

convert list of elements to tuple5, prevent index out of bounds

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.

Upvotes: 0

Views: 789

Answers (3)

Sasha O
Sasha O

Reputation: 3749

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!
}

Upvotes: 1

samthebest
samthebest

Reputation: 31533

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.

Upvotes: 1

Norbert Radyk
Norbert Radyk

Reputation: 2618

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)
    }
  }

Upvotes: 5

Related Questions