Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

multiply all array with array

0 views
Skip to first unread message

ibotty

unread,
Aug 29, 2003, 6:59:29 AM8/29/03
to
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 ;)

~ibotty

Martin DeMello

unread,
Aug 29, 2003, 7:21:52 AM8/29/03
to
ibotty <m...@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}

martin

angus

unread,
Aug 29, 2003, 8:11:39 AM8/29/03
to
> 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]

Wesley J. Landaker

unread,
Aug 29, 2003, 9:55:25 AM8/29/03
to

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

Wesley J. Landaker

unread,
Aug 29, 2003, 9:57:36 AM8/29/03
to

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... ;)

Wes

denis

unread,
Aug 29, 2003, 10:47:34 AM8/29/03
to
ibotty <m...@ibotty.net> wrote in message news:<10621549...@elch.in-berlin.de>...


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 :)

Ciao
Denis

ibotty

unread,
Aug 29, 2003, 11:08:34 AM8/29/03
to
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

unread,
Aug 29, 2003, 11:25:12 AM8/29/03
to

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| i*j}
p [1,2,3].mapwith([4,5,6], :*)

martin

Olivier Nenert

unread,
Aug 29, 2003, 11:26:17 AM8/29/03
to
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.


Sabby and Tabby

unread,
Aug 29, 2003, 7:54:35 PM8/29/03
to
Martin DeMello <martin...@yahoo.com> wrote:

> ibotty <m...@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| i*j}
> 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.

Charles Hixson

unread,
Aug 30, 2003, 2:06:47 PM8/30/03
to
Martin DeMello wrote:

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.

Hal Fulton

unread,
Aug 30, 2003, 2:09:43 PM8/30/03
to

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

Martin DeMello

unread,
Aug 30, 2003, 4:15:11 PM8/30/03
to
Sabby and Tabby <sabby...@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}

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

> 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

ibotty

unread,
Aug 30, 2003, 5:52:05 PM8/30/03
to
>>>> 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? ;)
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

Martin DeMello

unread,
Aug 31, 2003, 8:13:49 AM8/31/03
to
Martin DeMello <martin...@yahoo.com> wrote:
> Sabby and Tabby <sabby...@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}

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

Harry Ohlsen

unread,
Sep 1, 2003, 7:01:50 PM9/1/03
to
ibotty wrote:

> ... (well, cross product it


> should not necessarily define, too much specific to three dimension
> vectors, huh? ;)

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.

0 new messages