# Iterating over an area in pairs.

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

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

--------------------------------------------------
Think twice, code once.

Thaddeus L Olczyk, May 6, 2006

2. ### Robert KlemmeGuest

> 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

3. ### Ross BamfordGuest

On Sat, 06 May 2006 07:25:37 +0100, Robert Klemme <> 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]]

\$ 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
4. ### Martin DeMelloGuest

> 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
5. ### Sky YinGuest

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
6. ### Ross BamfordGuest

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
7. ### Robert KlemmeGuest

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
8. ### Ross BamfordGuest

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