23

I'm wondering if there's a way to do what I can do below with Python, in Ruby:

sum = reduce(lambda x, y: x + y, map(lambda x, y: x * y, weights, data))

I have two arrays of equal sizes with the weights and data but I can't seem to find a function similar to map in Ruby, reduce I have working.

6 Answers 6

14

@Michiel de Mare

Your Ruby 1.9 example can be shortened a bit further:

weights.zip(data).map(:*).reduce(:+)

Also note that in Ruby 1.8, if you require ActiveSupport (from Rails) you can use:

weights.zip(data).map(&:*).reduce(&:+)
Sign up to request clarification or add additional context in comments.

3 Comments

That doesn't work for me on Ruby 1.9.3 (ArgumentError): [1,2,3].zip([4,5,6]).map(:*)
@FelixRabe: It seems ruby has changed how the arguments get handled in this sort of proc. I don't really know any details, since I haven't touched ruby in a few years.
Ten or so years after you wrote this you could have shortened it to weights.zip(data).sum { |s,d| s*d }.
6

In Ruby 1.9:

weights.zip(data).map{|a,b| a*b}.reduce(:+)

In Ruby 1.8:

weights.zip(data).inject(0) {|sum,(w,d)| sum + w*d }

Comments

2

The Array.zip function does an elementwise combination of arrays. It's not quite as clean as the Python syntax, but here's one approach you could use:

weights = [1, 2, 3]
data = [4, 5, 6]
result = Array.new
a.zip(b) { |x, y| result << x * y } # For just the one operation

sum = 0
a.zip(b) { |x, y| sum += x * y } # For both operations

Comments

1

Ruby has a map method (a.k.a. the collect method), which can be applied to any Enumerable object. If numbers is an array of numbers, the following line in Ruby:

numbers.map{|x| x + 5}

is the equivalent of the following line in Python:

map(lambda x: x + 5, numbers)

For more details, see here or here.

Comments

1
weights = [1,2,3]
data    = [10,50,30]

require 'matrix'
Vector[*weights].inner_product Vector[*data] # => 200 

Comments

0

An alternative for the map that works for more than 2 arrays as well:

def dot(*arrays)
  arrays.transpose.map {|vals| yield vals}
end

dot(weights,data) {|a,b| a*b} 

# OR, if you have a third array

dot(weights,data,offsets) {|a,b,c| (a*b)+c}

This could also be added to Array:

class Array
  def dot
    self.transpose.map{|vals| yield vals}
  end
end

[weights,data].dot {|a,b| a*b}

#OR

[weights,data,offsets].dot {|a,b,c| (a*b)+c}

Comments

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.