Each_with_what_index?

Can you see the bug’a’boo in the following snippet?

a[1..-1].each_with_index do |t,i|
    puts "#{t} => #{a[i]}"
    # ...
end

Now, I understand why it happens, but nonethess I spent a good while tracking
it down (in a slightly more complex version). I guess that’s just the way it
has to be, but it is quite unintuitive.

-t0

Bugs can be like that sometimes, but there’s absolutely nothing
unintutive about that, unless you want Ruby to start guessing what you
really mean all the time :slight_smile:

Maybe this is better for you?

a.each_with_index do |t,i|
next if i == 0
puts “#{t} => #{a[i]}”
# …
end

Gavin

···

On Wednesday, December 3, 2003, 10:01:38 PM, T. wrote:

Can you see the bug’a’boo in the following snippet?

a[1..-1].each_with_index do |t,i|
    puts "#{t} => #{a[i]}"
    # ...
end

Now, I understand why it happens, but nonethess I spent a good while tracking
it down (in a slightly more complex version). I guess that’s just the way it
has to be, but it is quite unintuitive.

Hi –

Can you see the bug’a’boo in the following snippet?

No, it looks OK to me.

a[1..-1].each_with_index do |t,i|
    puts "#{t} => #{a[i]}"
    # ...
end

Now, I understand why it happens, but nonethess I spent a good while tracking
it down (in a slightly more complex version). I guess that’s just the way it
has to be, but it is quite unintuitive.

It’s doing exactly what you ask: you’ve send the message
“each_with_index” to an array (namely, a[1…-1]) and Ruby is acting
accordingly.

Did you want to do something more like:

(1…a.size).each {|i| puts “#{a[i]}” }

?

David

···

On Wed, 3 Dec 2003, T. Onoma wrote:


David A. Black
dblack@wobblini.net

Bugs can be like that sometimes, but there’s absolutely nothing
unintutive about that, unless you want Ruby to start guessing what you
really mean all the time :slight_smile:

Saying that there’s “absolutely nothing unintutive about that” is a real
stretch. Obviously, I have asked for certain indexes [1…-1], but we know
that # is really just a form of slice, so what we get is a new array, thus
reindexed form [0…a.length-2]. It’s understandable, but I sure wouldn’t call
it intuitive.

Maybe this is better for you?

a.each_with_index do |t,i|
next if i == 0
puts “#{t} => #{a[i]}”
# …
end

I did:

a[1…-1].each_with_index do |t,i|
puts “#{t} => #{a[i+1]}”
# …
end

Thinking it would be more efficient. Hmm…Or does this have a bug?

T.

···

On Wednesday 03 December 2003 12:23 pm, Gavin Sinclair wrote:

It’s doing exactly what you ask: you’ve send the message
“each_with_index” to an array (namely, a[1…-1]) and Ruby is acting
accordingly.

:slight_smile: David you crack me up! Of course. It always does Exactly what I’ve I
Asked. Unfortunately it rarely Does what I Mean! :wink:

Did you want to do something more like:

(1…a.size).each {|i| puts “#{a[i]}” }

Something like that would work too. In fact that’s probably a better, and
certainly a more traditional way to do it.

Thanks!
T.

···

On Wednesday 03 December 2003 03:21 pm, David A. Black wrote:

What you did was this:

a = [1, 2, 3]
b = a[1…-1]
b.each_with_index do |t, i|
puts “#{t} => #{a[i]}”
end

You are generating a new array that is a subset of an existing array
and then iterating over the new array with the new array’s indexes.
You then use that index to reference into the original array.
Obviously the values would be different.

···

On Dec 3, 2003, at 9:50 AM, T. Onoma wrote:

Saying that there’s “absolutely nothing unintutive about that” is a
real
stretch. Obviously, I have asked for certain indexes [1…-1], but we
know
that # is really just a form of slice, so what we get is a new
array, thus
reindexed form [0…a.length-2]. It’s understandable, but I sure
wouldn’t call
it intuitive.

Suppose if each_with_index allowed a range parameter
a.each_with_index(1…a.size) {|t,i|…}
Would that be worth an RCR? It looks sort of natural to me, but…

    Hugh
···

On Wed, 3 Dec 2003, T. Onoma wrote:

Saying that there’s “absolutely nothing unintutive about that” is a real
stretch. Obviously, I have asked for certain indexes [1…-1], but we know
that # is really just a form of slice, so what we get is a new array, thus
reindexed form [0…a.length-2]. It’s understandable, but I sure wouldn’t call
it intuitive.

But? Seems good to me too, as far as I know each_with_index doesn’t currently
take any parameters.

T.

···

On Wednesday 03 December 2003 04:13 pm, Hugh Sasse Staff Elec Eng wrote:

On Wed, 3 Dec 2003, T. Onoma wrote:

Saying that there’s “absolutely nothing unintutive about that” is a real
stretch. Obviously, I have asked for certain indexes [1…-1], but we know
that # is really just a form of slice, so what we get is a new array,
thus reindexed form [0…a.length-2]. It’s understandable, but I sure
wouldn’t call it intuitive.

Suppose if each_with_index allowed a range parameter
a.each_with_index(1…a.size) {|t,i|…}
Would that be worth an RCR? It looks sort of natural to me, but…

Hi –

Saying that there’s “absolutely nothing unintutive about that” is a real
stretch. Obviously, I have asked for certain indexes [1…-1], but we know
that # is really just a form of slice, so what we get is a new array, thus
reindexed form [0…a.length-2]. It’s understandable, but I sure wouldn’t call
it intuitive.

Suppose if each_with_index allowed a range parameter
a.each_with_index(1…a.size) {|t,i|…}
Would that be worth an RCR? It looks sort of natural to me, but…

Just for fun:

module Enumerable
def each_with_index(range=(0…size))
range.each {|i| yield at(i),i}
end
end

though it doesn’t do much for me. I guess I haven’t seen the problem
to which it would be a solution, and it seems to be based on a sort of
rollback of the original request (i.e., here’s a enumerable; give me
its elements and their indices; wait, actually, don’t act on the
receiver but on a subsequent restraint…). It feels inside-out to
me.

David

···

On Thu, 4 Dec 2003, Hugh Sasse Staff Elec Eng wrote:

On Wed, 3 Dec 2003, T. Onoma wrote:

David A. Black
dblack@wobblini.net

Hi –

Suppose if each_with_index allowed a range parameter
a.each_with_index(1…a.size) {|t,i|…}
Would that be worth an RCR? It looks sort of natural to me, but…

Just for fun:

module Enumerable
def each_with_index(range=(0…size))
range.each {|i| yield at(i),i}
end
end

Easier than I thought.

though it doesn’t do much for me. I guess I haven’t seen the problem
to which it would be a solution, and it seems to be based on a sort of

One place it could be used is with one array indexing k others,
where the indices are sorted based on {whatever happens to be of
interest}. But it is anything that responds_to?(each) so there may
be more applications than are dreamt of in my philosophy…

rollback of the original request (i.e., here’s a enumerable; give me
its elements and their indices; wait, actually, don’t act on the
receiver but on a subsequent restraint…). It feels inside-out to
me.

Do act on the receiver but…
“I want this book printed, but just the odd pages (then I’ll feed them
through again)…”

I think that was almost how the problem was framed: “I want all the
elements, well, except the zeroth, of course!”.

It does make it easier to change your mind about which ones, later.

David

David A. Black
dblack@wobblini.net

    Hugh
···

On Thu, 4 Dec 2003, David A. Black wrote:

On Thu, 4 Dec 2003, Hugh Sasse Staff Elec Eng wrote:

module Enumerable
def each_with_index(range=(0…size))
range.each {|i| yield at(i),i}
end
end

A couple problems there. First, the range from the original example
is 1…-1, which won’t work in the above code because treated as
a standalone range, it’s empty. Only when applied to the context
of the array size does it make sense.

You can fix that like this:

module Enumerable
def each_with_index(range=(0…size))
b, e, x = range.begin,range.end,range.exclude_end?
if b < 0 || e < 0
b += size if b < 0
e += size if e < 0
range = Range.new(b,e,x)
end
range.each {|i| yield at(i),i}
end
end

Then this works:

irb(main):012:0> a=[0,1,-1]
=> [0, 1, -1]
irb(main):013:0> a.each_with_index(1…-1) do |x, i| puts “#{i}: #{x}” end
1: 1
2: -1
=> 1…2

Secondly, and less importantly, it not obvious to me that
array.each_with_index(range) should iterate over the given subrange
of the array. What I would more expect is to iterate over all of
the array, but take the “index” values from the range instead of
using the real ones. Which is a much sillier idea, but that’s how
I read it.

-Mark

···

On Thu, Dec 04, 2003 at 04:09:59AM +0900, David A. Black wrote:

Just for fun:

Hi,

···

At Thu, 4 Dec 2003 10:42:07 +0900, Mark J. Reed wrote:

You can fix that like this:

module Enumerable
def each_with_index(range=(0…size))
b, e, x = range.begin,range.end,range.exclude_end?
if b < 0 || e < 0
b += size if b < 0
e += size if e < 0
range = Range.new(b,e,x)
end
range.each {|i| yield at(i),i}
end
end

Fundamentally, these work only with Array, not Enumerable.


Nobu Nakada