Cartesian product of arrays

understood. actually i have a VERY fast implementation already that
was written by Michael Neuman. to be so fast it's very ugly though :slight_smile:
want to see?

Yes please,
The API and the efficiency are both important for a potential standard
library,
(so the name should be carefully choosen !)
-- Maurice

Hello,

"Trans" <transfire@gmail.com> wrote/schrieb <1170111266.962275.227650@v45g2000cwv.googlegroups.com>:

> "Trans" <transf...@gmail.com> wrote/schrieb <1170083352.801941.114...@p10g2000cwp.googlegroups.com>:
> It was just my first attempt to implement it, and that somehow
> accidentally was the result. I'm not unlucky with it, at least it
> seems to work with just a few lines of code.

understood. actually i have a VERY fast implementation already that
was written by Michael Neuman. to be so fast it's very ugly though :slight_smile:
want to see?

I was curious enough to run both - my code and the one that you've
adapted from code by Michael Neuman - in irb, and my impression is,
that my code is even much faster. So if you're interested in providing
a really good library, please feel free to benchmark and chose the
best one according to your benchmark results.

Sorry that I did no benchmark myself (I'm still Ruby newbie); I just
run (1..15).cartesian_product((1..15),(1..15)) with both variants.

In addition I don't find my implementation ugly, so there's a real
chance to get several advantages at the same time :slight_smile:

Regards
  Thomas

···

On Jan 29, 3:53 pm, Thomas Hafner <tho...@hafner.NL.EU.ORG> wrote:

well, then can anyone tell me which one is the best?

···

--
Posted via http://www.ruby-forum.com/.

"karoyakani" <tj.takei@gmail.com> wrote/schrieb <1170049485.669713.169350@h3g2000cwc.googlegroups.com>:

def cartprod(*args)
  args.shift.cartprod(args)

                        ^^^^
    args.shift.cartprod(*args)
with the additional ``*'' would be better ...

end

Then both forms work as below:
p (1..2).cartprod((3..5), (6..8))
p cartprod([1,2],[3,4,5],[6,7,8])

... otherwise the second statement produces different output.
Very nice!

Further consideration would be to use a block for output formating:
e.g. replace result << [n] + a above to yield n, a and a block {|n,a| n
+a.join(' ')} for string concatination etc

Great, still more abstraction!

Regards
  Thomas

Here ya go....

require 'generator'

module Enumerable

  class << self

    # Provides the cross-product of two or more Enumerables.
    # This is the class-level method. The instance method
    # calls on this.

···

On Jan 30, 11:07 am, "diam" <d...@ensta.fr> wrote:

> understood. actually i have a VERY fast implementation already that
> was written by Michael Neuman. to be so fast it's very ugly though :slight_smile:
> want to see?

Yes please,
The API and the efficiency are both important for a potential standard
library,
(so the name should be carefully choosen !)
-- Maurice

    #
    # Enumerable.cross([1,2], [4], ["apple", "banana"])
    # #=> [[1, 4, "apple"], [1, 4, "banana"], [2, 4, "apple"], [2,
4, "banana"]]
    #
    # Enumerable.cross([1,2], [3,4])
    # #=> [[1, 3], [1, 4], [2, 3], [2, 4]]
    #
    #--
    # TODO Make a more efficient version just for Array (?)
    #++

    def cartesian_product(*enums, &block)
      raise if enums.empty?
      gens = enums.map{|e| Generator.new(e)}
      return if gens.any? {|g| g.end?}

      sz = gens.size
      res =
      tuple = Array.new(sz)

      loop do
        # fill tuple
        (0 ... sz).each { |i|
          tuple[i] = gens[i].current
        }
        if block.nil?
          res << tuple.dup
        else
          block.call(tuple.dup)
        end

        # step forward
        gens[-1].next
        (sz-1).downto(0) do |i|
          if gens[i].end?
            if i > 0
              gens[i].rewind
              gens[i-1].next
            else
              return res
            end
          end
        end
      end #loop
    end

    alias :cart, :cartesian_product
  end

  # The instance level version of <tt>Enumerable::cartesian_product</

.

  #
  # a =
  # [1,2].cart([4,5]){|elem| a << elem }
  # a #=> [[1, 4],[1, 5],[2, 4],[2, 5]]
  #
  #--
  # TODO Make a more efficient version just for Array (?)
  #++

  def cart(*enums, &block)
    Enumerable.cart(self, *enums, &block)
  end

  alias :cart, :cartesian_product
end

Very good!!! I will do so then.

Thanks, and I'll let you know how it turns out.
T.

···

On Jan 31, 2:05 pm, Thomas Hafner <tho...@hafner.NL.EU.ORG> wrote:

Hello,

"Trans" <transf...@gmail.com> wrote/schrieb <1170111266.962275.227...@v45g2000cwv.googlegroups.com>:

> On Jan 29, 3:53 pm, Thomas Hafner <tho...@hafner.NL.EU.ORG> wrote:
> > "Trans" <transf...@gmail.com> wrote/schrieb <1170083352.801941.114...@p10g2000cwp.googlegroups.com>:
> > It was just my first attempt to implement it, and that somehow
> > accidentally was the result. I'm not unlucky with it, at least it
> > seems to work with just a few lines of code.

> understood. actually i have a VERY fast implementation already that
> was written by Michael Neuman. to be so fast it's very ugly though :slight_smile:
> want to see?

I was curious enough to run both - my code and the one that you've
adapted from code by Michael Neuman - in irb, and my impression is,
that my code is even much faster. So if you're interested in providing
a really good library, please feel free to benchmark and chose the
best one according to your benchmark results.

Sorry that I did no benchmark myself (I'm still Ruby newbie); I just
run (1..15).cartesian_product((1..15),(1..15)) with both variants.

In addition I don't find my implementation ugly, so there's a real
chance to get several advantages at the same time :slight_smile:

Hello,

"Trans" <transf...@gmail.com> wrote/schrieb <1170111266.962275.227...@v45g2000cwv.googlegroups.com>:

> > "Trans" <transf...@gmail.com> wrote/schrieb <1170083352.801941.114...@p10g2000cwp.googlegroups.com>:
> > It was just my first attempt to implement it, and that somehow
> > accidentally was the result. I'm not unlucky with it, at least it
> > seems to work with just a few lines of code.

> understood. actually i have a VERY fast implementation already that
> was written by Michael Neuman. to be so fast it's very ugly though :slight_smile:
> want to see?

I was curious enough to run both - my code and the one that you've
adapted from code by Michael Neuman - in irb, and my impression is,
that my code is even much faster. So if you're interested in providing
a really good library, please feel free to benchmark and chose the
best one according to your benchmark results.

Very Good! And you are quite right. I must have gotten this confused
with some other function. I've put you code in, and credited you.
Thanks lots for this! There was only one downside in that using the
block form couldn't run on the each possibility as it is computed, but
that's okay. I just tied the block into the end result:

def cartesian_product(*enums, &block)
      result = []
      while != enums
        t, result = result,
        b, *enums = enums
        t.each do |a|
          b.each do |n|
            result << a + [n]
          end
        end
      end
      if block_given?
        result.each{ |e| block.call(e) }
      else
        result
      end
    end

Sorry that I did no benchmark myself (I'm still Ruby newbie); I just
run (1..15).cartesian_product((1..15),(1..15)) with both variants.

In addition I don't find my implementation ugly, so there's a real
chance to get several advantages at the same time :slight_smile:

Indeed! :slight_smile:

Thanks again,
T.

···

On Jan 31, 2:05 pm, Thomas Hafner <tho...@hafner.NL.EU.ORG> wrote:

> On Jan 29, 3:53 pm, Thomas Hafner <tho...@hafner.NL.EU.ORG> wrote:

Nanyang Zhan wrote:

well, then can anyone tell me which one is the best?

Unfortunately, these methods uses too much memory, storing the whole
cartesian product Array in memory even its elements are needed only one
at a time. One nicer alternative is the Cartesian module:

"The Cartesian module provide methods for the calculation of the
cartesian producted between two enumberable objects. It can also be
easily mixed in into any enumberable class, i.e. any class with
Enumerable module mixed in."

The Cartesian module is available at
http://rubyforge.org/projects/cartesian/

···

--
Posted via http://www.ruby-forum.com/\.

Nanyang Zhan wrote:

well, then can anyone tell me which one is the best?

Unfortunately, these methods use too much memory, storing the whole
cartesian product Array in memory even its elements are needed only one
at a time. A nicer alternative is the Cartesian module:

"The Cartesian module provide methods for the calculation of the
cartesian producted between two enumberable objects. It can also be
easily mixed in into any enumberable class, i.e. any class with
Enumerable module mixed in."

The Cartesian module is available at
http://rubyforge.org/projects/cartesian/

···

--
Posted via http://www.ruby-forum.com/\.

Err... fix the alias bug though (damn no-comma gets me every time!),
and the last def should be using the full name, ie. "def
cartesian_product".

T.

···

On Jan 31, 6:25 am, "Trans" <transf...@gmail.com> wrote:

On Jan 30, 11:07 am, "diam" <d...@ensta.fr> wrote:

> > understood. actually i have a VERY fast implementation already that
> > was written by Michael Neuman. to be so fast it's very ugly though :slight_smile:
> > want to see?

> Yes please,
> The API and the efficiency are both important for a potential standard
> library,
> (so the name should be carefully choosen !)
> -- Maurice

Here ya go....

Update: although gems releases are still being published at RubyForge as
well as RubyGems, the project is now hosted at GitHub and its new
homepage is http://adrianomitre.github.com/cartesian/website/index.html

···

--
Posted via http://www.ruby-forum.com/.