2015-12-30 2 views
4

У меня есть последовательность векторов двойников: val vectors = Seq[Vector[Double]]Сумма последовательности векторов в Scala

Я хотел бы суммировать все векторы в последовательности, т.е. val total = vectors.sum

Например, если у меня есть последовательность с двумя векторами [1,2] и [3,4], то результат должен быть [4,6]

Однако sum метод Vector типа требует неявного Numeric.

То, что я сейчас:

val total = vectors.reduce((one,two) => one.zip(two).map(tuple => tuple._1 + tuple._2)) 

Я новичок в Scala, но я считаю, это сбивает с толку, и я полагаю, что это, вероятно, неэффективна.

Есть ли лучший способ сделать это?

+0

Вы хотите 'Seq [Векторные [Double]]' или в 'Seq [(распашные, Двухместный)] '? –

+0

Я хочу только вектор [Двойной]. Если у меня есть Seq с двумя векторами [1,2] и [3,4], тогда я хочу [4,6] в качестве результата –

+1

Что делать, если есть «Вектор (1, 2, 3)»? Вы уверены, что 'Vector' - это тип данных, который вы хотите, а не' Tuple2'? Это не одно и то же. –

ответ

3

Этот хвост рекурсивная функция будет работать, даже если векторы имеют разную длину и могут быть применены для любого числового типа:

@scala.annotation.tailrec 
def recSum[T : Numeric](s : Iterable[Iterable[T]]) : List[T] = { 
    val goodVecs = s.filterNot(_.isEmpty) 

    if(goodVecs.isEmpty) 
    List.empty[T] 
    else 
    goodVecs.map(_.head).sum :: recSum(goodVecs.map(_.tail)) 
} 

Применив его к примеру:

recSum(Seq(Vector(1.0,2.0), Vector(3.0,4.0,5.0))) //List(4.0,6.0,5.0) 

recSum(Seq.empty[Vector[Double]]) // List() 
+0

'scala> Seq [Int](). Head java.util.NoSuchElementException: голова пустого списка' –

+0

@KevinMeredith Я не понимаю ваш комментарий. Каково было значение ввода, вызвавшее это исключение? –

+0

Моя ошибка не разрабатывается. 'Seq # head' не следует использовать, была моя точка зрения. См. Http://www.cis.upenn.edu/~cis194/spring13/lectures/03-rec-poly.html#total-and-partial-functions. –

1

Подход вы взяли в вашем первоначальном вопросе идет по тому же пути, что и я. Поскольку вы подняли озабоченность по поводу эффективности, мой ответ включает использование итераторов, так что операции вроде zip и map просто вернут новый итератор, а не перестраивают всю коллекцию. Я также адаптировал ваш подход к работе для любого ненулевого числа входных векторов.

Пример входных данных:

val vecs = Seq( 
    Vector(1,2,3,4,5), 
    Vector(2,3,4,5,6), 
    Vector(8,2,6,4,2), 
    Vector(2,8,4,8,8) 
) 

Первый шаг, трансформировать Seq [Vector] к Seq [итератора]

val iterators: Seq[Iterator[Int]] = vecs.map(_.iterator) 

reduce Теперь, что Seq в один итератора. Это очень похоже на то, что вы написали в своем оригинальный вопрос:

val sumIterator = iterators.reduce[Iterator[Int]]{ (itrA, itrB) => 
    // combine 2 of the iterators into a sum of their individual parts 
    // the resulting iterator will then be combined with the next iterator 
    // so you end up with a single iterator of the total sum for each 'column' 

    (itrA zip itrB) map { case (a, b) => a + b } 
} 

Теперь вы можете использовать sumIterator найти суммы каждого «столбца» в вашем «матрице».

sumIterator.toList 
// List(13, 15, 17, 21, 21) 
0

Снизить внутренние Vector сек с sum, затем уменьшить внешний Seq с sum:

scala> val vectors: Seq[Vector[Double]] = List(Vector(.1,.2),Vector(.3,.4)) 
vectors: Seq[Vector[Double]] = List(Vector(0.1, 0.2), Vector(0.3, 0.4)) 

scala> vectors.map(_.sum).sum 
res10 Double = 1.0