Carty product Ruby

class CartesianProduct include Enumerable # your code here end #Examples of use c = CartesianProduct.new([:a,:b], [4,5]) c.each { |elt| puts elt.inspect } # [:a, 4] # [:a, 5] # [:b, 4] # [:b, 5] c = CartesianProduct.new([:a,:b], []) c.each { |elt| puts elt.inspect } # (nothing printed since Cartesian product # of anything with an empty collection is empty) 

I'm new to ruby. And I understand how to define an instance method for a Cartesian product, but I have no clue about this. How should I build a class object to fulfill the requirement.

+6
source share
3 answers

I would not use a class for this, but preserving the structure of the question, I would write:

 class CartesianProduct include Enumerable def initialize(xs, ys) @xs = xs @ys = ys end def each return to_enum unless block_given? @xs.each do |x| @ys.each { |y| yield [x, y] } end end end 

Instead, I simply write xs.product(ys) or create my own Array#lazy_product if laziness was important (see this ticket ).

+6
source

I suggest using Array#product .

 [:a, :b].product [4,5] 

Which will give the result you want.

 irb(main):001:0> [:a, :b].product [4,5] => [[:a, 4], [:a, 5], [:b, 4], [:b, 5]] irb(main):002:0> 

If you need a lazy permutation generator, I wrote something like this before. But I warn you, if you have a large number of permutations for calculation, this may take some time. You should be able to take what you need from the first 40 to 45 lines of this file (this file was an experiment anyway).

The trick is to create counters using Ruby 1.9.2 to work with an array of arrays. Thus, you first create an enumerator that will endlessly cycle through the array, and in your array-array enumerator, you track the first set of output data and end the loop when it hits the second time. This was the only way to understand how to complete such a cycle.

 def infinite_iterator(array) Enumerator.new do |result| loop do array.cycle { |item| result << item } end end end def cartesian_iterator(data) Enumerator.new do |result| first = data.map { |p| p.next } result << first i = 1 parts = first.dup loop do parts[2-i] = data[2-i].next break if parts == first result << parts.join i = ((i + 1) % parts.size) end end end array = [ infinite_iterator([:a,:b]), infinite_iterator([4,5]) ] generator = cartesian_iterator(array) generator.each { |a| pa } 
+22
source

You need to define a each method in your class that calls yield for each product combination.

You can use Array#product , but it returns an array, so it is not lazy.

Ruby 2.0 has a proposal for Array.product that will do just that.

+6
source

Source: https://habr.com/ru/post/919803/


All Articles