У меня есть парная RDD, которая выглядит как
(a1, (a2, a3))
(b1, (b2, b3))
...
Я хочу сгладить значения, чтобы получить
(a1, a2, a3)
(b1, b2, b3)
...
В настоящее время я делаю
rddData.map(x => (x._1, x._2._1, x._2._2))
Есть ли лучший способ выполнить преобразование? Вышеупомянутое решение становится уродливым, если value
содержит много элементов вместо двух.
Всего 2 ответа
Когда я пытаюсь избежать всех уродливых номеров подчеркивания, которые идут с манипуляциями с кортежем, я хотел бы использовать случайную нотацию:
rddData.map { case (a, (b, c)) => (a, b, c) }
Вы также можете присвоить своим переменным значимые имена, чтобы сделать ваш код самодокументированным, а использование фигурных скобок означает, что у вас меньше вложенных круглых скобок.
EDIT: шаблон карты {case ...} довольно компактный и может использоваться для удивительно глубоких вложенных кортежей, пока структура известна во время компиляции. Если вы абсолютно, не можете знать структуру кортежа во время компиляции, то вот какой-то взломанный, медленный код, который, вероятно, может сгладить любые произвольно вложенные кортежи ... пока не будет больше 23 элементов. Он работает, рекурсивным образом преобразуя каждый элемент кортежа в список, разбивая его на один список, а затем используя страшное отражение, чтобы преобразовать список обратно в кортеж, как показано здесь .
def flatten(b:Product): List[Any] = {
b.productIterator.toList.flatMap {
case x: Product => flatten(x)
case y: Any => List(y)
}
}
def toTuple[Any](as:List[Any]):Product = {
val tupleClass = Class.forName("scala.Tuple" + as.size)
tupleClass.getConstructors.apply(0).newInstance(as.map(_.asInstanceOf[AnyRef]):_*).asInstanceOf[Product]
}
rddData.map(t => toTuple(flatten(t)))
Нет лучшего способа. 1-й ответ эквивалентен:
val abc2 = xyz.map{ case (k, v) => (k, v._1, v._2) }
что эквивалентно вашему собственному примеру.