Scala-эквивалент R's Mapply?

Я пришел из R, поэтому я привык использовать семейство функций R *apply.

Функции list.foreach(_.fun) и list.map(_.fun) в Scala очень похожи на функцию lapply(list, fun) в R тем, что обе они итеративно выполняют функцию над каждым элементом списка.

Однако в R также есть функция mapply(fun, list1, list2, ...), которая полезна, когда у вас есть несколько списков и вы хотите применить функцию к первому элементу каждого, второму элементу каждого и так далее. Например, если бы у меня была функция add(x, y, z) и два списка x=(1, 2, 3), y=(2, 3, 4) и z=(3, 4, 5), mapply(add, x, y, z) вернул бы (6, 9, 12).

Есть ли в Scala какой-либо эквивалент R mapply без использования цикла for?


person Shuklaswag    schedule 02.07.2016    source источник
comment
Может кто-нибудь объяснить, почему за этот вопрос проголосовали? Я задаю вопрос по программированию, который нелегко было найти в Google и, похоже, не имел дубликата в Stack Overflow. Голосование против без комментариев не способствует сообществу.   -  person Shuklaswag    schedule 02.07.2016
comment
Я не минусовал вас, однако, поскольку я также не люблю минусы без комментариев, и у меня достаточно представителей, чтобы понять, почему люди голосуют за закрытие вашего поста, я могу вам сказать. Они указывают на правило, согласно которому вопросы, в которых нас просят порекомендовать или найти книгу, инструмент, библиотеку программного обеспечения, учебник или другой сторонний ресурс, не относятся к теме Stack Overflow, поскольку они, как правило, привлекают самоуверенные ответы и спам. Вместо этого опишите проблему и то, что уже было сделано для ее решения.   -  person Hack-R    schedule 02.07.2016
comment
Как насчет этого: dahl.byu.edu/software/rscala/rscala-jss. pdf . Вы можете просто использовать mapply в Scala!   -  person Hack-R    schedule 02.07.2016
comment
Я не знаю Scala, но это похоже на тот же общий вопрос.   -  person Rich Scriven    schedule 02.07.2016
comment
@Hack-R: Это действительно интересный пакет! Я думаю, что на самом деле переключаться на программирование R для такой проблемы — это излишество, но это здорово, что такая возможность существует.   -  person Shuklaswag    schedule 02.07.2016
comment
@RichardScriven: После прочтения вашей ссылки кажется, что zipped это то, что я ищу. Спасибо!   -  person Shuklaswag    schedule 02.07.2016


Ответы (1)


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

scala> List(List(1,2,3),List(5,6,7),List(14,13,12)).transpose
res3: List[List[Int]] = List(List(1, 5, 14), List(2, 6, 13), List(3, 7, 12))

scala> List(List(1,2,3),List(5,6,7),List(14,13,12)).transpose.map(_.sum)
res4: List[Int] = List(20, 21, 22)

Примечание. transpose требует, чтобы все вложенные коллекции имели одинаковый размер.


Дополнение к вашему комментарию.

Я не уверен, что вы понимаете, что такое zipped. Он преобразует 2 подколлекции внутри кортежа (Tuple2) в единую коллекцию кортежей, каждый из которых затем может быть передан функции, которая принимает 2 параметра заданных типов. Это также доступно для 3 подколлекций внутри Tuple3, становящихся коллекцией троек, но это предел.

Кроме того, я не знаю, почему вы думаете, что «zipped — это один вызов функции, а не два». Если вы следуете link, предложенный Ричардом Скривеном в его комментарии, и сравните два предложенных решения, вы увидите, что они имеют одинаковое количество шагов/операторов.

На мой взгляд, преимущества/недостатки распределяются следующим образом:

  • Если вы имеете дело с коллекциями разных типов, скажем, Seq[Int] и Seq[Char], то вам нужно получить их zipped перед применением к ним функции «объединителя»: f(i1,c1), затем f(i2,c2), затем f(i3,c3) и т. д.
  • Ни один из подходов не справляется с подколлекциями разного размера. transpose вызовет исключение, а zipped просто проигнорирует все элементы за пределами максимального индекса наименьшей подколлекции.
  • Если ваша функция «объединитель» принимает более трех аргументов, вы не можете использовать zipped.
  • Если ваш «объединитель» принимает коллекцию в качестве входных данных, то transpose, вероятно, будет лучшим/более простым вариантом.
person jwvh    schedule 02.07.2016
comment
Умное решение! Вы знаете, лучше ли это решение, чем использование zipped? Конечный результат кажется таким же, за исключением того, что zipped — это один вызов функции, а не два. - person Shuklaswag; 02.07.2016
comment
Моя оценка zipped была добавлена ​​к предложенному ответу. - person jwvh; 02.07.2016