Multiply all array with array

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

atm, i use a block to traverse thru every single element, but this still
makes one big or 2 small lines.
(e. g.: c =[]; a.each_with_index{ |ix| c[ix] = a[ix] * b[ix] } )

this should be way more elegant :wink:

~ibotty

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

martin

···

ibotty me@ibotty.net wrote:

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

a.zip(b).map { |x,y| x*y } # => [4, 10, 18]

Apparently, ibotty recently wrote:

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

atm, i use a block to traverse thru every single element, but this still
makes one big or 2 small lines.
(e. g.: c =; a.each_with_index{ |ix| c[ix] = a[ix] * b[ix] } )

this should be way more elegant :wink:

I don’t know if this is more elegant to you or not, but here is another way:

c = a.zip(b).map {|x| x[0] * x[1]}

Wes

ibotty me@ibotty.net wrote in message news:1062154916.838157@elch.in-berlin.de…

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

atm, i use a block to traverse thru every single element, but this still
makes one big or 2 small lines.
(e. g.: c =; a.each_with_index{ |ix| c[ix] = a[ix] * b[ix] } )

this should be way more elegant :wink:

you can use the Enumerable#zip and Enumerable#collect methods:

c = a.zip(b).collect{|a_elt, b_elt| a_elt*b_elt}

i dont see more elegant :slight_smile:

Ciao
Denis

Apparently, Martin DeMello recently wrote:

···

ibotty me@ibotty.net wrote:

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

Hey, this is just like what I just posted, except better! =)

(That’s what I get for replying before reading the rest of the thread… :wink:

Wes

thx all ya guys,

is there a builtin function in array.rb (that i have missed).

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

this is indeed much more elegant.

but because array * array is not defined, me thinks. one could implement
(this simple case) this way.

just my 2¢, though

~ibotty

Martin DeMello wrote:

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

martin

But isn’t that the wrong answer?
I thought that [1, 2, 3] * [4, 5, 6] would be:
[ [4, 5, 6],
[8, 10, 12],
[12, 15, 18]
] or some such (I might have reversed the arguments–and I don’t think
it’s commutative. [Admittedly, it’s been a few decades since I did such
math.]). And if you meant the dot product rather than the cross
product, you would get a scalar.

···

ibotty me@ibotty.net wrote:

thx all ya guys,

is there a builtin function in array.rb (that i have missed).

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

this is indeed much more elegant.

but because array * array is not defined, me thinks. one could implement
(this simple case) this way.
but I think most people (or at least I) would expect a cartesian product
as the result of this operator… it would be much more useful because it
would work with any two arrays,
not just two arrays with the same size. (oh well it could also work like
you say with arrays of different sizes if we fill with zeros the shorter
one :))

cheers…

Olivier.

Here’s a handy generalisation of the method:

class Array
def mapwith(*args, &block)
if block_given?
zip(*args).collect {|i, j| yield i, j}
else
f = args.pop
zip(*args).collect {|i, j| i.send(f, j)}
end
end
end

p [1,2,3].mapwith([4,5,6]) {|i,j| ij}
p [1,2,3].mapwith([4,5,6], :
)

martin

···

ibotty me@ibotty.net wrote:

thx all ya guys,

is there a builtin function in array.rb (that i have missed).

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

this is indeed much more elegant.

but because array * array is not defined, me thinks. one could implement
(this simple case) this way.

Charles Hixson wrote:

Martin DeMello wrote:

before i spent to many words describing something so simple:

say, i have:
a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

is there a builtin function in array.rb (that i have missed).

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

martin

But isn’t that the wrong answer?
I thought that [1, 2, 3] * [4, 5, 6] would be:
[ [4, 5, 6],
[8, 10, 12],
[12, 15, 18]
] or some such (I might have reversed the arguments–and I don’t think
it’s commutative. [Admittedly, it’s been a few decades since I did such
math.]). And if you meant the dot product rather than the cross
product, you would get a scalar.

I think this is what the original poster wanted. He doesn’t
seem to be asking for a cross product OR a dot product as
far as I can tell, but just a nice idiomatic way of doing
a specific operation.

Hal

···

ibotty me@ibotty.net wrote:

Not quite, but for parallel traversing made easier

a.zip(b).map {|i, j| i*j}

this is indeed much more elegant.

but because array * array is not defined, me thinks. one could implement
(this simple case) this way.

In APL, * and other operators work like this, element-by-element.

Here’s a handy generalisation of the method:

class Array
def mapwith(*args, &block)
if block_given?
zip(*args).collect {|i, j| yield i, j}
else
f = args.pop
zip(*args).collect {|i, j| i.send(f, j)}
end
end
end

p [1,2,3].mapwith([4,5,6]) {|i,j| ij}
p [1,2,3].mapwith([4,5,6], :
)

Should #mapwith work with 3 or more arrays like #zip does?

p [1,2,3].mapwith([4,5,6], [7,8,9]) {|i,j,k| i*j+k}

Allowing #zip to take a block has been discussed before. Here’s yet
another implementation:

class Array
alias _zip zip
def zip(*args)
if block_given?
_zip(*args).map {|a| yield a}
else
_zip(*args)
end
end
end

p [1,2,3].zip([4,5,6], [7,8,9]) {|i,j,k| i*j+k}

Unfortunately, it doesn’t allow taking a symbol to an operator (:*)
like #mapwith does.

···

Martin DeMello martindemello@yahoo.com wrote:

ibotty me@ibotty.net wrote:

a = [1,2,3] and b = [4,5,6]
and i want to get another array, with c[ix] = a[ix] * b[ix].
(i want to get c = [4,10,18])

a.zip(b).map {|i, j| i*j}
But isn’t that the wrong answer?
[…]
And if you meant the dot product rather than the cross
product, you would get a scalar.

I think this is what the original poster wanted. He doesn’t
seem to be asking for a cross product OR a dot product as
far as I can tell, but just a nice idiomatic way of doing
a specific operation.

we do have a Vector (defined in matrix.rb (in 1.6 at least))
this Vector should define cross and dot product (well, cross product it
should not necessarily define, too much specific to three dimension
vectors, huh? :wink:
so in short, i think this a product of two arrays should not be a cross or
dot product. never. use a vector instead, if you want to.

btw: this is not meant to be rude, but why put something in array, when it
belongs to something else.

~ibotty

Should #mapwith work with 3 or more arrays like #zip does?

p [1,2,3].mapwith([4,5,6], [7,8,9]) {|i,j,k| i*j+k}

Right you are. I’ll rework it in the a.m. - too sleepy right now :slight_smile:

Allowing #zip to take a block has been discussed before. Here’s yet
another implementation:

class Array
alias _zip zip
def zip(*args)
if block_given?
_zip(*args).map {|a| yield a}
else
_zip(*args)
end
end
end

p [1,2,3].zip([4,5,6], [7,8,9]) {|i,j,k| i*j+k}

Unfortunately, it doesn’t allow taking a symbol to an operator (:*)
like #mapwith does.

The symbol was my main motivation for writing it, actually - map {|x,y|
x*y} just felt redundant.

martin

···

Sabby and Tabby sabbyxtabby@yahoo.com wrote:

ibotty wrote:

… (well, cross product it
should not necessarily define, too much specific to three dimension
vectors, huh? :wink:

Perhaps we need a Tensor class :-).

If there was such one, maybe I’d finally have a hope of understanding those darned things!

Harry O.

class Array
def mapwith(*args, &block)
if block_given?
zip(*args).collect {|i| yield *i}
else
f = args.pop
zip(*args).collect {|i, *j| i.send(f, *j)}
end
end
end

p [1,2,3].mapwith([4,5,6], [7,8,9]) {|i,j,k| i*j+k}
p [[1],[2],[3]].mapwith([4,5,6], [7,8,9], :push)

martin

···

Martin DeMello martindemello@yahoo.com wrote:

Sabby and Tabby sabbyxtabby@yahoo.com wrote:

Should #mapwith work with 3 or more arrays like #zip does?

p [1,2,3].mapwith([4,5,6], [7,8,9]) {|i,j,k| i*j+k}