2

I come from a R background, so I'm accustomed to using R's *apply family of functions.

Scala's list.foreach(_.fun) and list.map(_.fun) functions are very similar to R's lapply(list, fun) function, in that they both iteratively perform a function over each element of a list.

However, R also has a function mapply(fun, list1, list2, ...), which is useful when one has several lists and wants to apply a function over the first element of each, the second element of each, and so on. For example, if I had a function add(x, y, z), and two lists x=(1, 2, 3), y=(2, 3, 4), and z=(3, 4, 5), mapply(add, x, y, z) would return (6, 9, 12).

Does Scala have any equivalent to R's mapply, without using a for-loop?

Shuklaswag
  • 1,003
  • 1
  • 10
  • 27
  • Can someone explain why this question was downvoted? I'm asking a programming question which was not easily Google-able and did not seem to have a duplicate on Stack Overflow. Downvoting without commenting does not contribute to the community. – Shuklaswag Jul 02 '16 at 02:27
  • I did not downvote you, however since I also dislike downvotes without comments and I have enough rep to see why people are voting to close your post I can tell you. They are pointing to the rule that says "Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it" – Hack-R Jul 02 '16 at 02:29
  • How about this: https://dahl.byu.edu/software/rscala/rscala-jss.pdf . You can just use `mapply` in Scala! – Hack-R Jul 02 '16 at 02:34
  • 1
    I don't know Scala, but [this](http://stackoverflow.com/questions/8322191/apply-function-on-each-elements-in-one-list-using-element-from-others-list-as-ar) seems like the same general question. – Rich Scriven Jul 02 '16 at 02:46
  • 1
    @Hack-R: That's a really interesting package! I think it's overkill to actually switch to R programming for an issue like this, but it's cool that option exists. – Shuklaswag Jul 02 '16 at 03:17
  • @RichardScriven: After reading your link, it seems like `zipped` is what I'm looking for. Thanks! – Shuklaswag Jul 02 '16 at 03:22

1 Answers1

2

There is no analogous routine in the Standard Library, but you can get close:

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)

Note: transpose requires all sub-collections have the same size.


Followup to your comment.

I'm not sure you understand what zipped is. It transforms 2 sub-collections, inside a tuple (Tuple2), into a single collection of tuples, each of which can then be given to a function that takes 2 parameters of the given types. This is also available for 3 sub-collections, inside a Tuple3, becoming a collection of triples, but that's the limit.

Also, I don't know why you think "zipped is one function call as opposed to two". If you follow the link Richard Scriven suggested in his comment, and compare the two solutions offered, you'll see that they have the same number of steps/statements.

As I see it, the advantages/disadvantages breakdown as follows:

  • If you're dealing with collections of different types, say Seq[Int] and Seq[Char], then you'll want to get them zipped before applying the "combiner" function to them: f(i1,c1) then f(i2,c2) then f(i3,c3) etc.
  • Neither approach handles sub-collections of different sizes well. transpose will throw an exception while zipped simply ignores all elements beyond the max-index of the smallest sub-collection.
  • If your "combiner" function takes more than three arguments then you can't use zipped.
  • If your "combiner" takes a collection as input, then transpose is probably the better/easier option.
Community
  • 1
  • 1
jwvh
  • 50,871
  • 7
  • 38
  • 64
  • Clever solution! Do you know if this solution is any better than using `zipped`? The end result seems the same, except that `zipped` is one function call as opposed to two. – Shuklaswag Jul 02 '16 at 03:23
  • My assessment of `zipped` has been added to offered answer. – jwvh Jul 02 '16 at 05:22