Iterating over an area in pairs.

Discussion in 'Ruby' started by Thaddeus L Olczyk, May 6, 2006.

  1. Is there a simple way to iterate over an array by taking any two pairs
    ( for this question I need one where I iterate over any two
    combinations, but if someone can show how to do it by taking pairs so
    that no two pairsa are duplicated that would be cool too ).

    --------------------------------------------------
    Thaddeus L. Olczyk, PhD
    Think twice, code once.
     
    Thaddeus L Olczyk, May 6, 2006
    #1
    1. Advertising

  2. Thaddeus L Olczyk wrote:
    > Is there a simple way to iterate over an array by taking any two pairs
    > ( for this question I need one where I iterate over any two
    > combinations, but if someone can show how to do it by taking pairs so
    > that no two pairsa are duplicated that would be cool too ).


    1.8.4 doc states that there is a method each_slice that does what you
    need, but my cygwin version doesn't seem to contain it:

    robert@fussel ~
    $ ruby -e '[1,2].each_slice(2){|*xx| p x}'
    -e:1: undefined method `each_slice' for [1, 2]:Array (NoMethodError)

    robert@fussel ~
    $ ruby --version
    ruby 1.8.4 (2005-12-24) [i386-cygwin]

    You can work around in a number of ways, just an example

    irb(main):004:0> a=[1,2,10,30]
    => [1, 2, 10, 30]
    irb(main):005:0> 0.step(a.length-1, 2) {|i| puts a,a[i+1],"--"}
    1
    2
    --
    10
    30
    --
    => 0

    Kind regards

    robert
     
    Robert Klemme, May 6, 2006
    #2
    1. Advertising

  3. Thaddeus L Olczyk

    Ross Bamford Guest

    On Sat, 06 May 2006 07:25:37 +0100, Robert Klemme <> wrote:

    > Thaddeus L Olczyk wrote:
    >> Is there a simple way to iterate over an array by taking any two pairs
    >> ( for this question I need one where I iterate over any two
    >> combinations, but if someone can show how to do it by taking pairs so
    >> that no two pairsa are duplicated that would be cool too ).

    >
    > 1.8.4 doc states that there is a method each_slice that does what you
    > need, but my cygwin version doesn't seem to contain it:
    >
    > robert@fussel ~
    > $ ruby -e '[1,2].each_slice(2){|*xx| p x}'
    > -e:1: undefined method `each_slice' for [1, 2]:Array (NoMethodError)
    >


    In 1.8 you need to require enumerator:

    $ ruby -renumerator -e '[1,2,3,4].each_slice(2){|*x| p x}'
    [[1, 2]]
    [[3, 4]]

    In 1.9 you're already set:

    $ ruby9 -e '[1,2,3,4].each_slice(2){|*x| p x}'
    [[1, 2]]
    [[3, 4]]

    Depending on what the OP wanted, each_cons might be useful, too:

    $ ruby -renumerator -e '[1,2,3,4].each_cons(2){|*x| p x}'
    [[1, 2]]
    [[2, 3]]
    [[3, 4]]

    --
    Ross Bamford -
     
    Ross Bamford, May 6, 2006
    #3
  4. Thaddeus L Olczyk <> wrote:
    > Is there a simple way to iterate over an array by taking any two pairs
    > ( for this question I need one where I iterate over any two
    > combinations, but if someone can show how to do it by taking pairs so
    > that no two pairsa are duplicated that would be cool too ).


    Coincidentally, I wrote this yesterday (it's called Permutation because
    I wanted to leave room to expand it into a generalised
    permutation/combination library, but for now all I needed was the
    combine method):

    class Permutation
    def initialize(n)
    @array = n
    end

    def combine(k)
    combinations(@array,k) {|i|
    yield i
    }
    end

    def combinations(ary, k)
    if k == 1
    ary.each {|i| yield }
    return
    end
    if ary.length == k
    yield ary
    return
    else
    car, *cdr = ary
    combinations(cdr, k-1) {|i| yield ([car] + i)}
    combinations(cdr, k) {|i| yield i}
    end
    end
    end

    Use as:
    a = Permutation.new(ary)
    a.combine(2) {|i,j| }

    martin
     
    Martin DeMello, May 7, 2006
    #4
  5. Thaddeus L Olczyk

    Sky Yin Guest

    A side question. I've noticed that:
    =>[[1,2], [3,4]].each{|x,y| p x,y}
    >>1
    >>2
    >>3
    >>4


    but:
    =>[[1,2],[3,4]].each{|x| p x}
    >>[1,2]
    >>[3,4]


    moreover:
    =>[[1,2],[3,4]].each{|x,| p x}
    >>1
    >>3


    I couldn't find the rule of such sub-array matching in doc. Is it a
    special syntax?
     
    Sky Yin, May 7, 2006
    #5
  6. Thaddeus L Olczyk

    Ross Bamford Guest

    On Sun, 07 May 2006 17:52:19 +0100, Sky Yin <> wrote:

    > A side question. I've noticed that:
    > =>[[1,2], [3,4]].each{|x,y| p x,y}
    >>> 1
    >>> 2
    >>> 3
    >>> 4

    >
    > but:
    > =>[[1,2],[3,4]].each{|x| p x}
    >>> [1,2]
    >>> [3,4]

    >
    > moreover:
    > =>[[1,2],[3,4]].each{|x,| p x}
    >>> 1
    >>> 3

    >
    > I couldn't find the rule of such sub-array matching in doc. Is it a
    > special syntax?
    >


    Block arguments are handled using regular Ruby assignment rules, so
    everything from *splat to nested assignment is supported. One place I
    often find this useful is (contrived example):

    [[:a,1],[:b,2],[:c,3]].inject({}) { |hsh,(sym, num)| hsh.merge!({ sym =>
    num }) }
    # => {:b=>2, :a=>1, :c=>3}

    You'll find more in the Pickaxe, 2nd ed, p90-93 (or from the first edition
    at http://www.rubycentral.com/book/tut_expressions.html - I doubt much has
    changed in this regard.)

    Hope that helps,
    --
    Ross Bamford -
     
    Ross Bamford, May 7, 2006
    #6
  7. Ross Bamford <> wrote:
    > Block arguments are handled using regular Ruby assignment rules, so
    > everything from *splat to nested assignment is supported. One place I
    > often find this useful is (contrived example):
    >
    > [[:a,1],[:b,2],[:c,3]].inject({}) { |hsh,(sym, num)| hsh.merge!({ sym
    > => num }) }
    > # => {:b=>2, :a=>1, :c=>3}


    I think I now why you use merge! but I'd prefer this one - a tad more
    unelegant but also a tad more efficient:

    [[:a,1],[:b,2],[:c,3]].inject({}) { |h,(k, v)| h[k]=v; h}
    => {:b=>2, :c=>3, :a=>1}

    Kind regards

    robert
     
    Robert Klemme, May 8, 2006
    #7
  8. Thaddeus L Olczyk

    Ross Bamford Guest

    On Mon, 08 May 2006 18:31:36 +0100, Robert Klemme <> wrote:

    > Ross Bamford <> wrote:
    >> Block arguments are handled using regular Ruby assignment rules, so
    >> everything from *splat to nested assignment is supported. One place I
    >> often find this useful is (contrived example):
    >>
    >> [[:a,1],[:b,2],[:c,3]].inject({}) { |hsh,(sym, num)| hsh.merge!({ sym
    >> => num }) }
    >> # => {:b=>2, :a=>1, :c=>3}

    >
    > I think I now why you use merge! but I'd prefer this one - a tad more
    > unelegant but also a tad more efficient:
    >
    > [[:a,1],[:b,2],[:c,3]].inject({}) { |h,(k, v)| h[k]=v; h}
    > => {:b=>2, :c=>3, :a=>1}
    >


    Yeah, I started throwing merge! in there lately, mostly for that reason
    but I guess it probably is quite inefficient really, especially as the
    hash grows...

    Thanks,
    --
    Ross Bamford -
     
    Ross Bamford, May 9, 2006
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ShaunJ
    Replies:
    4
    Views:
    663
    James Kanze
    Jan 22, 2008
  2. carl
    Replies:
    5
    Views:
    2,379
    James Kanze
    Nov 25, 2009
  3. FireAphis

    Iterating list in pairs

    FireAphis, Aug 8, 2007, in forum: Ruby
    Replies:
    12
    Views:
    192
    FireAphis
    Aug 9, 2007
  4. Jerry Krinock
    Replies:
    7
    Views:
    316
    Eric Pozharski
    Sep 12, 2008
  5. Marek
    Replies:
    7
    Views:
    216
Loading...

Share This Page