array and hash combine methods

G

glen

Just thought I'd post a solution I came up with to finding
combinations (as in, permutations and combinations) of arrays. For
example, combining:

[1,2] and [3,4,5]

should return:

[[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]]

which is easy enough. But I wanted something that combine several
arrays at once, ie:

[[1,2],[3,4,5],[6,7]].combine
=> [[1, 3, 6], [1, 3, 7], [1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7],
[2, 3, 6], [2, 3, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7]]

I had a look around and couldn't find anything that worked for more
than two arrays, so I wrote my own:

class Array
#expects self to be an array of arrays, returns all the combinations possible
def combine
#checks
output_length = 1
periods = []
reverse.each { |sub_arr|
periods << output_length
raise "combine needs an array of arrays!" if !sub_arr.is_a? Array
raise "combine is meaningless unless all the sub_arrays have at
least one element!" if sub_arr.length == 0
output_length *= sub_arr.length
}
periods.reverse!
output = (1..output_length).map { Array.new(length) }
output.each_index { |i|
periods.each_index { |j|
output[j] = self[j][(i/periods[j])%self[j].length]
}
}
output
end
end

And the corresponding hash method:

class Hash
#expects a hash eg. {a=>[1,2], b=>[3,4]}
#returns an array eg. [{a=>1,b=>3}, {a=>1,b=4}, {a=>2,b=>3}, {a=>2,b=4}]
def combine
values.combine.map { |comb|
Hash[*keys.zip(comb).inject([]) { |arr,e| arr + e }]
}
end
end

I'd love to hear other solutions to this problem - and where I should
have looked to find them... Oh and if anyone has suggestions for a
better name than 'combine', that'd be great.

Cheers,
-glen.
 
O

Olivier

Le jeudi 14 d=E9cembre 2006 02:22, glen a =E9crit=A0:
Just thought I'd post a solution I came up with to finding
combinations (as in, permutations and combinations) of arrays. For
example, combining:

[1,2] and [3,4,5]

should return:

[[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]]

which is easy enough. But I wanted something that combine several
arrays at once, ie:

[[1,2],[3,4,5],[6,7]].combine
=3D> [[1, 3, 6], [1, 3, 7], [1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7],
[2, 3, 6], [2, 3, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7]]

There is a Enumerable.combinations method in ruby facets which works like=20
this. Take a look at :

http://facets.rubyforge.org/api/core/classes/Enumerable.html#M000555

=2D-
Olivier
 
J

Juan Matias

glen said:
Just thought I'd post a solution I came up with to finding
combinations (as in, permutations and combinations) of arrays. For
example, combining:

[1,2] and [3,4,5]

should return:

[[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]]

which is easy enough. But I wanted something that combine several
arrays at once, ie:

[[1,2],[3,4,5],[6,7]].combine
=> [[1, 3, 6], [1, 3, 7], [1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7],
[2, 3, 6], [2, 3, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7]]

And why not something like:

[1,2].combine([3,4]).combine([5,6,7])

I do that with this code:

class Array
def combine(otherArray)
aux = []
self.each do |self_elem|
otherArray.each do |other_elem|
aux << [self_elem,other_elem]
end
end
aux.map {|elem| elem.flatten }
end
end

Juan Matias
 
P

Phrogz

Juan, it would appear that glen posted this question/tip 3.5 years
ago. Any reason you were responding to it now? (Which, in turn, lured
me into responding. :)
 
J

Juan Matias

Gavin said:
Juan, it would appear that glen posted this question/tip 3.5 years
ago. Any reason you were responding to it now? (Which, in turn, lured
me into responding. :)

Sure Gavin, I'm looking for something like that and found this post.
Maybe result useful to someone. You have another solution for this?
Thanks
 
K

Kamal Ahmed

The examples seem to be missing=0AIf there is code snippets, it would help.=
=0A-Kamal.=0A=0A=0A=0A=0A________________________________=0AFrom: Juan Mati=
as <[email protected]>=0ATo: ruby-talk ML <[email protected]>=0ASen=
t: Tue, June 8, 2010 12:33:24 AM=0ASubject: Re: array and hash combine meth=
ods=0A=0AGavin Kistner wrote:=0A> On Jun 7, 9:52=EF=BF=BDpm, Juan Matias <j=
(e-mail address removed)> wrote:=0A>> glen wrote:=0A>> > Just thought I'd post a =
solution I came up with to finding=0A>> > combinations (as in, permutations=
and combinations) of arrays. For=0A>> > example, combining:=0A> =0A> Juan,=
it would appear that glen posted this question/tip 3.5 years=0A> ago. Any =
reason you were responding to it now? (Which, in turn, lured=0A> me into re=
sponding. :)=0A=0ASure Gavin, I'm looking for something like that and found=
this post. =0AMaybe result useful to someone. You have another solution fo=
r this?=0AThanks=0A-- =0APosted via http://www.ruby-forum.com/.
 
R

Robert Klemme

2010/6/8 Juan Matias said:
glen said:
Just thought I'd post a solution I came up with to finding
combinations (as in, permutations and combinations) of arrays. For
example, combining:

[1,2] and [3,4,5]

should return:

[[1,3],[1,4],[1,5],[2,3],[2,4],[2,5]]

which is easy enough. But I wanted something that combine several
arrays at once, ie:

[[1,2],[3,4,5],[6,7]].combine
=3D> [[1, 3, 6], [1, 3, 7], [1, 4, 6], [1, 4, 7], [1, 5, 6], [1, 5, 7],
[2, 3, 6], [2, 3, 7], [2, 4, 6], [2, 4, 7], [2, 5, 6], [2, 5, 7]]

And why not something like:

=A0[1,2].combine([3,4]).combine([5,6,7])

I do that with this code:

class Array
=A0def combine(otherArray)
=A0 =A0aux =3D []
=A0 =A0self.each do |self_elem|
=A0 =A0 =A0otherArray.each do |other_elem|
=A0 =A0 =A0 =A0aux << [self_elem,other_elem]
=A0 =A0 =A0end
=A0 =A0end
=A0 =A0aux.map {|elem| elem.flatten }
=A0end
end

I'd rather do this:

module Enumerable
def combine(enum)
if block_given?
each do |*a|
enum.each do |*b|
yield *a, *b
end
end
self
else
enum_for:)combine, enum)
end
end
end

[1,2].combine([3,4]) do |*a|
p a
end

puts "--------------"

[1,2].combine([3,4]).each do |*a|
p a
end

puts "--------------"

[1,2].combine([3,4]).combine([5,6]) do |*a|
p a
end

puts "--------------"

[1,2].combine([3,4]).combine([5,6]).each do |*a|
p a
end

Kind regards

robert


--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
J

Juan Matias

Robert said:
2010/6/8 Juan Matias said:
�[1,2].combine([3,4]).combine([5,6,7])
� �end
� �aux.map {|elem| elem.flatten }
�end
end

I'd rather do this:

module Enumerable
def combine(enum)
if block_given?
each do |*a|
enum.each do |*b|
yield *a, *b
end
end
self
else
enum_for:)combine, enum)
end
end
end

[1,2].combine([3,4]) do |*a|
p a
end

puts "--------------"

[1,2].combine([3,4]).each do |*a|
p a
end

puts "--------------"

[1,2].combine([3,4]).combine([5,6]) do |*a|
p a
end

puts "--------------"

[1,2].combine([3,4]).combine([5,6]).each do |*a|
p a
end

Kind regards

robert

Great, I'll probe it,also I add a fix to my code:

class Array
def combine(otherArray)
aux = []
return otherArray if self.empty? #this line
self.each do |self_elem|
otherArray.each do |other_elem|
aux << [self_elem,other_elem]
end
end
aux.map {|elem| elem.flatten }
end
end

Juan Matias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,079
Latest member
ElidaWarin

Latest Threads

Top