4

In Ruby, how can one multiply every element in one array by every element in another array, such that:

a = [1,2,3]

b = [4,5,6]

c = a*b = [4,5,6,8,10,12,12,15,18]
2
  • 4
    I see now why you selected an answer so quickly. The author of that question asked you to do that just a few minutes after you posted the question! It is very bad form for him to have done that. He would not have done so had the question been posted by an experienced SO member, because he knows his request would not have fallen on deaf ears. I suggest that in future you wait at least a couple of hours, as you don't want to discourage others from posting answers or short-circuit those who are still working on their answers. There's no rush... Commented Dec 11, 2018 at 5:37
  • @CarySwoveland the OP appreciated the answer and said that it solved the problem. Its author in return asked if the OP could accept it, even providing a link to help section which explains how accepting works in detail. I see no bad form here. Commented Dec 11, 2018 at 9:36

4 Answers 4

10

For a nice abstraction, can get cartesian product using product:

a.product(b).map { |aa, bb| aa * bb }
Sign up to request clarification or add additional context in comments.

8 Comments

When I see the code like this (once a month at least,) I always wonder what’s wrong with Enumerable#map_reduce to be introduced in Ruby core? :)
Do you (or does a reader) know why Array#product returns an array rather than an enumerator? An enumerator would have obvious advantages in applications where product is chained to an Enumerable method. (I expect the reason is forehead-slapping simple.)
@CarySwoveland I am positive it’s legacy; fwiw, you always are free to a.enum_for(:product, b).
Thanks, mudsie, er @AlekseiMatiushkin That makes sense and thanks for the code (which I've tucked away).
BTW, zip is even worse – it just returns (a useless) nil when a block is given.
|
5

This solution makes use of Matrix methods to compute (and then flatten) the outer product of two vectors.

require 'matrix'

(Matrix.column_vector(a) * Matrix.row_vector(b)).to_a.flatten
  #=> [4, 5, 6, 8, 10, 12, 12, 15, 18]

Like the other two answers to date, this produces a temporary array, which when flattened (if not already flattened) contains a.size**2 elements. If a is so large that this results in a storage problem, you could use a pair of enumerators instead:

a.each_with_object([]) { |aa,arr| b.each { |bb| arr << aa*bb } }
  #=> [4, 5, 6, 8, 10, 12, 12, 15, 18]

The enumerators are as follows.

enum_a = a.each_with_object([])
  #=> #<Enumerator: [1, 2, 3]:each_with_object([])>
aa, arr = enum_a.next
  #=> [1, []]
aa, arr = enum_a.next
  #=> [2, []]
...

enum_b = b.each
  #=> #<Enumerator: [4, 5, 6]:each>
bb = enum_b.next
  #=> 4
bb = enum_b.next
  #=> 5
...

See Enumerator#next. This is how enumerators pass elements to their blocks.

The method Enumerable#each_with_object is very convenient and not as complex as it may initially seem. For the most part it just saves two lines of code from the following.

arr = []
a.each { |aa| b.each { |bb| arr << aa*bb } }
arr

2 Comments

"the cross-products are all done in C" – are you sure? The source code for matrix.rb looks as if it is implemented in Ruby.
@Stefan, as I was reading the code at the link you gave you could have knocked me over with a feather. Why? Why? Not why the feather, but why write each and every Matrix method in Ruby? The idea of writing numerically demanding methods such as Matrix#lup_decomposition in Ruby boggles the mind. I had assumed an optimized public-domain matrix library written in C had been used (with Ruby wrappers). That also would have been a lot easier than reinventing the wheel.
2

Tried with following,

a.product(b).map { |x| x.inject(&:*) }

Amazingly following also solve it,

a.map { |x| b.map(&x.method(:*)) }.flatten

3 Comments

The former is a shallow copy of the answer given by @Amadan and the latter is the exact copy of [not the best here] accepted answer. Downvoted.
Use (:*) in your first answer and flat_map in your second answer.
@SagarPandya I personally dislike passing a symbol argument to reduce since it is allowed by this method only, all of a sudden, while using Symbol#to_proc is the common approach used widely among the whole ruby core.
-3

This is not beautiful but returns what you want.

a.map{|aa| b.map{|bb| bb * aa}}.flatten

12 Comments

I would never, never, never upvote an answer given by anyone who asks a newbie SO for it after just a few minutes. Shame!
Thanks for your advice. You are right. I just thought telling how to use StackOverflow is a great behavior.
Correction to my earlier comment: "...who asks an SO newbie to mark their answer as selected after just a few minutes."
@Sagar, the answer is correct, so I don't think it deserves downvotes.
New users sometimes don't know that answers can be accepted. So if a new user says "thanks, that works" (aka solved the problem) but doesn't accept the answer, it's perfectly fine to ask them to do so.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.