Accessing index inside map

#> i'd like to double the element values except those loc on
#the 2nd and 5th
#> indices eg.

···

nobuyoshi nakada [mailto:nobuyoshi.nakada@ge.com] wrote:

#
#$ ruby -renumerator -e 'p
#(1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ?
#x : x*2}'
#[2, 4, 3, 8, 10, 6]

Hi Nobu,

Wow, cool. But my brain is very tiny compared to other rubyist brains.

i was hoping for something straight like,

[1,2,3,4,5,6].map{|x,i|[2,5].include?(i) ? x : x*2}

=>[2, 4, 3, 8, 10, 6]

Maybe you can hack one for dumb rubyists like me.

thanks and kind regards -botp

#
#--
#Nobu Nakada
#

Peña, Botp wrote:

···

nobuyoshi nakada [mailto:nobuyoshi.nakada@ge.com] wrote:

#> i'd like to double the element values except those loc on
#the 2nd and 5th
#> indices eg.
#
#$ ruby -renumerator -e 'p
#(1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ?
#x : x*2}'
#[2, 4, 3, 8, 10, 6]

Hi Nobu,

Wow, cool. But my brain is very tiny compared to other rubyist brains.

i was hoping for something straight like,

[1,2,3,4,5,6].map{|x,i|[2,5].include?(i) ? x : x*2}

=>[2, 4, 3, 8, 10, 6]

Maybe you can hack one for dumb rubyists like me.

Err, are you kidding? Enumerator isn't really that difficult - and you
don't need to modify Hash or other classes. It's a simple wrapper
delegating each to each_with_index. That simple.

Regards

    robert

Peña, Botp wrote:

nobuyoshi nakada wrote:

#> i'd like to double the element values except those loc on
#the 2nd and 5th
#> indices eg.
#
#$ ruby -renumerator -e 'p
#(1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ?
#x : x*2}'
#[2, 4, 3, 8, 10, 6]

Hi Nobu,

Wow, cool. But my brain is very tiny compared to other rubyist brains.

i was hoping for something straight like,

>[1,2,3,4,5,6].map{|x,i|[2,5].include?(i) ? x : x*2}
=>[2, 4, 3, 8, 10, 6]

i=-1;[1,2,3,4,5,6].map{|x|[2,5].include?(i+=1) ? x : x*2}
#=> [2, 4, 3, 8, 10, 6]

You can, of course, use this idiom to emulate *_with_index
functionality for (almost?) any iterator method.

daz

···

--

Never seek simplicity where complexity will suffice.
- (paraphrase :wink:

Hi --

···

On Fri, 8 Jul 2005, Robert Klemme wrote:

Peña, Botp wrote:

nobuyoshi nakada [mailto:nobuyoshi.nakada@ge.com] wrote:

#> i'd like to double the element values except those loc on
#the 2nd and 5th
#> indices eg.
#
#$ ruby -renumerator -e 'p
#(1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ?
#x : x*2}'
#[2, 4, 3, 8, 10, 6]

Hi Nobu,

Wow, cool. But my brain is very tiny compared to other rubyist brains.

i was hoping for something straight like,

[1,2,3,4,5,6].map{|x,i|[2,5].include?(i) ? x : x*2}

=>[2, 4, 3, 8, 10, 6]

Maybe you can hack one for dumb rubyists like me.

Err, are you kidding? Enumerator isn't really that difficult - and you
don't need to modify Hash or other classes. It's a simple wrapper
delegating each to each_with_index. That simple.

I'd still like to see #man_with_index added to Enumerable.

David

--
David A. Black
dblack@wobblini.net

[My first reply contained a typo and also, at least on my machine,
some garbage characters that screw it up in my mail client. So....]

I'd still like to see #map_with_index added to Enumerable.

David

···

On Fri, 8 Jul 2005, Robert Klemme wrote:

Peña, Botp wrote:

nobuyoshi nakada [mailto:nobuyoshi.nakada@ge.com] wrote:

#> i'd like to double the element values except those loc on
#the 2nd and 5th
#> indices eg.
#
#$ ruby -renumerator -e 'p
#(1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ?
#x : x*2}'
#[2, 4, 3, 8, 10, 6]

Hi Nobu,

Wow, cool. But my brain is very tiny compared to other rubyist brains.

i was hoping for something straight like,

[1,2,3,4,5,6].map{|x,i|[2,5].include?(i) ? x : x*2}

=>[2, 4, 3, 8, 10, 6]

Maybe you can hack one for dumb rubyists like me.

Err, are you kidding? Enumerator isn't really that difficult - and you
don't need to modify Hash or other classes. It's a simple wrapper
delegating each to each_with_index. That simple.

--
David A. Black
dblack@wobblini.net

Hi,

#$ ruby -renumerator -e 'p
#(1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ?
#
#[2, 4, 3, 8, 10, 6]

Hi Nobu,

Wow, cool. But my brain is very tiny compared to other rubyist brains.

i was hoping for something straight like,

[1,2,3,4,5,6].map{|x,i|[2,5].include?(i) ? x : x*2}

=>[2, 4, 3, 8, 10, 6]

Maybe you can hack one for dumb rubyists like me.

Err, are you kidding? Enumerator isn't really that difficult - and you
don't need to modify Hash or other classes. It's a simple wrapper
delegating each to each_with_index. That simple.

We have vague plan to make enumerating method to return Enumerator
when no block is given in the future, so that

  require 'enumerator'
  (1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ? x : x*2}

would be

  (1..6).each_with_index.map{|x,i|[2,5].include?(i) ? x : x*2}

then. It's much simpler isn't it?

              matz.

···

In message "Re: accessing index inside map" on Fri, 8 Jul 2005 19:20:48 +0900, "Robert Klemme" <bob.news@gmx.net> writes:

"index" implies an ordering, which maps by definition don't have.
Shouldn't that be something along the lines of "#map_with_key"?

But point taken; it seems a natural thing, regardless of actual name,
to be in Enumerable.

···

On 7/8/05, David A. Black <dblack@wobblini.net> wrote:

Hi --

I'd still like to see #man_with_index added to Enumerable.

Wow - I'd love to see that. Any potential drawbacks?

martin

···

Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

We have vague plan to make enumerating method to return Enumerator
when no block is given in the future, so that

  require 'enumerator'
  (1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ? x : x*2}

would be

  (1..6).each_with_index.map{|x,i|[2,5].include?(i) ? x : x*2}

then. It's much simpler isn't it?

We have vague plan to make enumerating method to return Enumerator
when no block is given in the future,

It's much simpler isn't it?

+1

Dan

Hi,

At Fri, 8 Jul 2005 23:02:11 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:147565]:

We have vague plan to make enumerating method to return Enumerator
when no block is given in the future, so that

  require 'enumerator'
  (1..6).enum_for(:each_with_index).map{|x,i|[2,5].include?(i) ? x : x*2}

would be

  (1..6).each_with_index.map{|x,i|[2,5].include?(i) ? x : x*2}

then. It's much simpler isn't it?

Is this plan going on?

I noticed that #map and #collect return an Array if no block
is given, instead of raising an exception.

Index: enum.c

···

===================================================================
RCS file: /cvs/ruby/src/ruby/enum.c,v
retrieving revision 1.58
diff -U2 -p -r1.58 enum.c
--- enum.c 30 Jun 2005 16:45:33 -0000 1.58
+++ enum.c 12 Jul 2005 03:54:56 -0000
@@ -18,4 +18,63 @@ VALUE rb_mEnumerable;
static ID id_each, id_eqq, id_cmp;

+#ifndef BUILTIN_ENUMERATOR
+#define BUILTIN_ENUMERATOR 1
+#endif
+
+#if BUILTIN_ENUMERATOR
+#define Init_enumerator static init_enumerator
+#include "ext/enumerator/enumerator.c"
+#undef Init_enumerator
+#else
+static ID id_enumerator;
+#endif
+
+void
+Init_enumerator()
+{
+#if BUILTIN_ENUMERATOR
+ char *src = ruby_sourcefile = rb_source_filename("enumerator");
+ init_enumerator();
+ rb_provide(src);
+#else
+ id_enumerator = rb_intern("Enumerator");
+ rb_autoload(rb_mEnumerable, id_enumerator, "enumerator");
+#endif
+}
+
+static VALUE
+enumeratorize(argc, argv, obj)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+{
+ VALUE enum_method = ID2SYM(rb_frame_this_func());
+#if BUILTIN_ENUMERATOR
+ VALUE enum_obj = enumerator_allocate(rb_cEnumerator);
+ struct enumerator *ptr = enumerator_ptr(enum_obj);
+
+ ptr->method = rb_obj_method(obj, enum_method);
+ if (rb_block_given_p()) {
+ ptr->proc = rb_block_proc();
+ ptr->iter = enumerator_iter_i;
+ }
+ else {
+ ptr->iter = (VALUE (*) _((VALUE, struct enumerator *)))rb_yield;
+ }
+ if (argc) ptr->args = rb_ary_new4(argc, argv);
+
+ return enum_obj;
+#else
+ VALUE enumerator = rb_const_get(rb_mEnumerable, id_enumerator);
+ VALUE args = rb_ary_new2(argc + 2);
+
+ RARRAY(args)->ptr[0] = obj;
+ RARRAY(args)->ptr[1] = enum_method;
+ MEMCPY(RARRAY(args)->ptr + 2, argv, VALUE, argc);
+ RARRAY(args)->len = argc + 2;
+ return rb_class_new_instance(RARRAY(args)->len, RARRAY(args)->ptr, enumerator);
+#endif
+}
+
VALUE
rb_each(obj)
@@ -115,4 +174,6 @@ enum_find(argc, argv, obj)

     rb_scan_args(argc, argv, "01", &if_none);
+ if (!rb_block_given_p())
+ return enumeratorize(argc, argv, obj);
     rb_iterate(rb_each, obj, find_i, (VALUE)&memo);
     if (memo != Qundef) {
@@ -152,6 +213,9 @@ enum_find_all(obj)
     VALUE obj;
{
- VALUE ary = rb_ary_new();
+ VALUE ary;
     
+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
+ ary = rb_ary_new();
     rb_iterate(rb_each, obj, find_all_i, ary);

@@ -184,6 +248,9 @@ enum_reject(obj)
     VALUE obj;
{
- VALUE ary = rb_ary_new();
+ VALUE ary;
     
+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
+ ary = rb_ary_new();
     rb_iterate(rb_each, obj, reject_i, ary);

@@ -226,7 +293,10 @@ enum_collect(obj)
     VALUE obj;
{
- VALUE ary = rb_ary_new();
+ VALUE ary;
+
+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);

- rb_iterate(rb_each, obj, rb_block_given_p() ? collect_i : collect_all, ary);
+ ary = rb_ary_new();
+ rb_iterate(rb_each, obj, collect_i, ary);

     return ary;
@@ -344,4 +414,6 @@ enum_partition(obj)
     VALUE ary[2];

+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
     ary[0] = rb_ary_new();
     ary[1] = rb_ary_new();
@@ -477,4 +549,6 @@ enum_sort_by(obj)
     long i;

+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
     if (TYPE(obj) == T_ARRAY) {
   ary = rb_ary_new2(RARRAY(obj)->len);
@@ -764,5 +838,6 @@ enum_min_by(obj)
     VALUE memo[2];

- rb_need_block();
+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
     memo[0] = Qundef;
     memo[1] = Qnil;
@@ -807,5 +882,6 @@ enum_max_by(obj)
     VALUE memo[2];

- rb_need_block();
+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
     memo[0] = Qundef;
     memo[1] = Qnil;
@@ -845,4 +921,6 @@ enum_member(obj, val)
     VALUE memo[2];

+ if (!rb_block_given_p()) return enumeratorize(1, &val, obj);
+
     memo[0] = val;
     memo[1] = Qfalse;
@@ -882,5 +960,6 @@ enum_each_with_index(obj)
     VALUE memo = 0;

- rb_need_block();
+ if (!rb_block_given_p()) return enumeratorize(0, 0, obj);
+
     rb_iterate(rb_each, obj, each_with_index_i, (VALUE)&memo);
     return obj;
Index: inits.c

RCS file: /cvs/ruby/src/ruby/inits.c,v
retrieving revision 1.9
diff -U2 -p -r1.9 inits.c
--- inits.c 19 Dec 2003 03:58:57 -0000 1.9
+++ inits.c 12 Jul 2005 03:49:43 -0000
@@ -19,4 +19,5 @@ void Init_Comparable _((void));
void Init_Dir _((void));
void Init_Enumerable _((void));
+void Init_enumerator _((void));
void Init_Exception _((void));
void Init_syserr _((void));
@@ -81,4 +82,5 @@ rb_call_inits()
     Init_GC();
     Init_marshal();
+ Init_enumerator();
     Init_version();
}

--
Nobu Nakada

Hi --

Hi --

I'd still like to see #man_with_index added to Enumerable.

"index" implies an ordering, which maps by definition don't have.
Shouldn't that be something along the lines of "#map_with_key"?

But point taken; it seems a natural thing, regardless of actual name,
to be in Enumerable.

Actually you're right about the ordering, and I think it should not be
in Enumerable. Hash#each_with_index has always struck me as pointless
for that reason: it just slaps essentially arbitrary integers on an
unordered collection. It also has always struck me as odd that
Enumerable has #each_with_index but lacks #index.

What I'd really like to see would be #each_with_index removed from
Enumerable, and pushed down to Array and other classes that need it
(like #index), and then #map_with_index added to Array too.

I think there's an RCR about this, probably, somewhere... possibly
rejected... :slight_smile: There's also been a lot of discussion here and
elsewhere about things like whether "enumerable" has to mean
"associated serially with integers", whether hashes should really be
understood as enumerable, whether hash keys are the equivalent of
array indices or whether, if hashes have a numerical "index", that
index is the equivalent of an array index, and if so, why hashes need
that extra layer of indexing, etc. (That's also come up in connection
with what an Array#to_hash method would do.)

I don't have any definitive answers, but I think there's room to clear
up the ambiguous status of the concept "index" as it is manifested in
Enumerable.

David

···

On Fri, 8 Jul 2005, Michael Campbell wrote:

On 7/8/05, David A. Black <dblack@wobblini.net> wrote:

--
David A. Black
dblack@wobblini.net

Michael Campbell wrote:

Hi --

I'd still like to see #man_with_index added to Enumerable.

"index" implies an ordering, which maps by definition don't have.
Shouldn't that be something along the lines of "#map_with_key"?

But point taken; it seems a natural thing, regardless of actual name,
to be in Enumerable.

Key is ambiguous with Hashes... Apart from that: I'm not really sure
whether I like that idea. The basic property of an Enumerable is that it
can be enumerated with each. There are no guarantees about order etc.
each_with_index is really only there to simplify counting. If you want
map_with_index then you'd probably have to provide inject_with_index,
find_with_index etc. Personally I think that map_with_index is rarely
used to justify adding this to the std lib. Just my 0.02 EUR of course.

Btw, another variant for mapping with index:

enum.inject() {|ar,el| ar << ([0,3].include?(ar.size) ? el : el*2) }

Kind regards

    robert

···

On 7/8/05, David A. Black <dblack@wobblini.net> wrote:

Excerpts from Michael Campbell's mail of 8 Jul 2005 (EDT):

···

On 7/8/05, David A. Black <dblack@wobblini.net> wrote:
> I'd still like to see #man_with_index added to Enumerable.

"index" implies an ordering, which maps by definition don't have.
Shouldn't that be something along the lines of "#map_with_key"?

"Map" here means "collect", not "Hash".

--
William <wmorgan-ruby-talk@masanjin.net>

Hi,

  (1..6).each_with_index.map{|x,i|[2,5].include?(i) ? x : x*2}

then. It's much simpler isn't it?

Is this plan going on?

I noticed that #map and #collect return an Array if no block
is given, instead of raising an exception.

I agree with the plan, so that someone come up with the implementation
before I do, I'd glad to merge it. ... boy, you did that.

I think it's a good chance. Can you merge enumerator in the following
steps?

  * merge ext/enumerator/enumerator.c to enum.c
  * remove ext/enumerator directory.
  * patch enum.c as you did.

              matz.

···

In message "Re: accessing index inside map" on Tue, 12 Jul 2005 12:56:50 +0900, nobuyoshi nakada <nobuyoshi.nakada@ge.com> writes:

Hi --

Michael Campbell wrote:

Hi --

I'd still like to see #man_with_index added to Enumerable.

"index" implies an ordering, which maps by definition don't have.
Shouldn't that be something along the lines of "#map_with_key"?

But point taken; it seems a natural thing, regardless of actual name,
to be in Enumerable.

Key is ambiguous with Hashes... Apart from that: I'm not really sure
whether I like that idea. The basic property of an Enumerable is that it
can be enumerated with each. There are no guarantees about order etc.
each_with_index is really only there to simplify counting. If you want
map_with_index then you'd probably have to provide inject_with_index,
find_with_index etc. Personally I think that map_with_index is rarely
used to justify adding this to the std lib. Just my 0.02 EUR of course.

I'm not a stickler for symmetry (my slogan for Ruby is "The triumph of
balance over symmetry" :slight_smile: but it does seem a little arbitrary to have
it recognized that #each_with_index is important for arrays, and #map
is important, but #map_with_index isn't. (I emphasize "arrays"; I've
never seen a case where it was needed or useful for hashes.) I don't
think there's any implication that you'd have to have *_with_index.
Nor any demand: I've never seen anyone implement #find_with_index
(what exactly would it do? :slight_smile: but I've seen many of
Array#each_with_index.

David

···

On Fri, 8 Jul 2005, Robert Klemme wrote:

On 7/8/05, David A. Black <dblack@wobblini.net> wrote:

--
David A. Black
dblack@wobblini.net

Excerpts from William Morgan's mail of 8 Jul 2005 (EDT):

Excerpts from Michael Campbell's mail of 8 Jul 2005 (EDT):
> > I'd still like to see #man_with_index added to Enumerable.
>
> "index" implies an ordering, which maps by definition don't have.
> Shouldn't that be something along the lines of "#map_with_key"?

"Map" here means "collect", not "Hash".

Whoops, I may have read too much into your reply. Sorry.

Anyways, as Robert Klemme points out, the index is often useful in
counting, so I'd be favor of putting map_with_index in Enumerable.

···

> On 7/8/05, David A. Black <dblack@wobblini.net> wrote:

--
William <wmorgan-ruby-talk@masanjin.net>

David A. Black wrote:
[...]

I don't have any definitive answers, but I think there's room to clear
up the ambiguous status of the concept "index" as it is manifested in
Enumerable.

In history, there was a hack submitted to ruby-core which tried to
implement a "block index" which supplied an automatically incrementing
counter to each invocation of *any* iterator.
The discussion turned into one about syntax rather than the concept.
Obviously, when the interpreter is hacked, some syntax might have to be
chosen to expose the index accessor.
I chose for myself (which is the author's prerogative and kind of essential).

So the analogue of this snippet:

   [1,2,3,4,5,6].map_with_index! do |e, ix|
     [2, 5].include?(ix) ? e : e*2
   end

was proposed to be:

   [1,2,3,4,5,6].map! do |e|.ix
     [2, 5].include?(ix) ? e : e*2
   end

In short, #each_with_index is scrapped and you use the standard #each
(or #map or any of the other methods taking a block) with an index/counter
magically available, on demand, within the block.

One could implement a fixed name like '_index_' or one of those Perl
thingies beginning with $ having local scope (as $1, $2 etc.) or any
number of alternatives; the principle is the same.

Two typically useful applications are:

   HUGE_ARRAY.each do |elem|.elnum
     break if $DBG && elnum > 500 # seen enough
     # stuff
   end

   IO.foreach() do |line|.linum
     # stuff where line number is useful (duh!)
   end

One major factor that has bugged me is the lack of symmetry
between #each and #e_w_i which discourages temporary changes.

h = {:a => 1, :b => 2, :c => 3}
# Current conversion of Hash#each to #each_with_index

h.each {|ek, ev| p [ek , ev ]}
h.each_with_index {|e, idx| p [e[0], e[1], idx]}
# ^_________^ :slight_smile: :slight_smile: ^^_^ :slight_smile:
# A B C D C E

# A. Change the method name to a much longer one.
# B. Name the index variable.
# C. Hash#each gives key and value -- #each_with_index
# passes these as a two-element array into the first
# block parameter. Specify which element.
# D. The name you chose for the second block parameter of each
# will, probably, need changing (if you used, say, 'key, val').
# E. Use the index variable.

Compared to this (with a wishful block index variable):

h.each {|ek, ev| p [ek, ev ]}
h.each {|ek, ev|.xv p [ek, ev, xv]}
# :slight_smile: ^_
# B E

Name it ... use it. (=== *_with_index)

In the interpreter, there'd be an integer in each BLOCK
struct which gets incremented before each iteration.
Not too expensive ?

One final gripe -- if you need a counter inside a block,
it's quicker to maintain your own than use #e_w_i.
(Do reply if this is incorrect.)

···

#--------------------------------------
require 'benchmark'
include Benchmark

arr = Array.new(100000)

bm(7) do |x|
  x.report('eachA') do
    ixj = 0; arr.each {|e| ixj += 1}
  end
  x.report('e_w_i') do
    arr.each_with_index {|e, dmy| dmy}
  end
  x.report('eachB') do # same as 'eachA'
    ixj = 0; arr.each {|e| ixj += 1}
  end
end
#--------------------------------------

BTW, I had to remove my local patch because it was sooo
usable that it was integrating into my style.

daz

Hi,

At Tue, 12 Jul 2005 13:08:33 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:147835]:

I think it's a good chance. Can you merge enumerator in the following
steps?

  * merge ext/enumerator/enumerator.c to enum.c
  * remove ext/enumerator directory.
  * patch enum.c as you did.

Enumerator needs its own initialization routine to be called
after Init_GC() got run, so one alternative Would be to move
enumerator.c to the top directory.

Of course, they are still small enough to merge.

Which is better?

···

--
Nobu Nakada

David A. Black wrote:

Hi --

Michael Campbell wrote:

Hi --

I'd still like to see #man_with_index added to Enumerable.

"index" implies an ordering, which maps by definition don't have.
Shouldn't that be something along the lines of "#map_with_key"?

But point taken; it seems a natural thing, regardless of actual
name, to be in Enumerable.

Key is ambiguous with Hashes... Apart from that: I'm not really sure
whether I like that idea. The basic property of an Enumerable is
that it can be enumerated with each. There are no guarantees about
order etc. each_with_index is really only there to simplify
counting. If you want map_with_index then you'd probably have to
provide inject_with_index, find_with_index etc. Personally I think
that map_with_index is rarely used to justify adding this to the std
lib. Just my 0.02 EUR of course.

I'm not a stickler for symmetry (my slogan for Ruby is "The triumph of
balance over symmetry" :slight_smile: but it does seem a little arbitrary to have
it recognized that #each_with_index is important for arrays, and #map
is important, but #map_with_index isn't. (I emphasize "arrays"; I've
never seen a case where it was needed or useful for hashes.) I don't
think there's any implication that you'd have to have *_with_index.
Nor any demand: I've never seen anyone implement #find_with_index
(what exactly would it do? :slight_smile: but I've seen many of
Array#each_with_index.

What about removing this completely from Enumerable and doing it like
this:

class Indexer
  include Enumerable

  def initialize(obj)
    # @meth = meth
    @obj = obj
  end

  def each
    i = 0
    @obj.each {|*a| yield *(a << i); i+=1}
    self
  end
end

module Enumerable
  def indexer() Indexer.new(self) end
end

aa=[10,20,30]

=> [10, 20, 30]

aa.indexer.each {|a,i| printf "%4d. %s\n", i, a}

   0. 10
   1. 20
   2. 30
=> #<Indexer:0x1017edc8 @obj=[10, 20, 30]>

aa.indexer.map {|a,i| a*i}

=> [0, 20, 60]

aa.indexer.inject() {|ar,(a,i)| ar << sprintf( "%4d. %s", i, a)}

=> [" 0. 10", " 1. 20", " 2. 30"]

hh={10=>:a, 20=>:b, 30=>:c}

=> {30=>:c, 20=>:b, 10=>:a}

hh.indexer.each {|(k,v),i| printf "%4d. %s => %s\n", i, k, v}

   0. 30 => c
   1. 20 => b
   2. 10 => a
=> #<Indexer:0x101a1940 @obj={30=>:c, 20=>:b, 10=>:a}>

hh.indexer.map {|(k,v),i| "#{k}=>#{v}" * i}

=> ["", "20=>b", "10=>a10=>a"]

hh.indexer.inject() {|ar,((k,v),i)| ar << sprintf( "%4d. %s => %s",

i, k, v)}
=> [" 0. 30 => c", " 1. 20 => b", " 2. 10 => a"]

Admittedly the last example looks a bit awkward - but #inject is not easy
anyway and it stays consistend with the others.

Kind regards

    robert

···

On Fri, 8 Jul 2005, Robert Klemme wrote:

On 7/8/05, David A. Black <dblack@wobblini.net> wrote:

daz wrote:

h.each {|ek, ev| p [ek , ev ]}
h.each_with_index {|e, idx| p [e[0], e[1], idx]}
# ^_________^ :slight_smile: :slight_smile: ^^_^ :slight_smile:
# A B C D C E

How about:

irb(main):012:0> class Hash
irb(main):013:1> alias_method :orig_each, :each
irb(main):014:1> def each
irb(main):015:2> index = 0
irb(main):016:2> orig_each do |ek, ev|
irb(main):017:3* yield ek, ev, index
irb(main):018:3> index += 1
irb(main):019:3> end
irb(main):020:2> end
irb(main):021:1> end
=> nil
irb(main):022:0> h = {:a => 1, :b => 2, :c => 3}
=> {:c=>3, :a=>1, :b=>2}
irb(main):023:0> h.each {|ek, ev| p [ek , ev ]}
[:c, 3]
[:a, 1]
[:b, 2]
=> {:c=>3, :a=>1, :b=>2}
irb(main):026:0> h.each {|ek, ev, idx| p [ek, ev, idx]}
[:c, 3, 0]
[:a, 1, 1]
[:b, 2, 2]
=> {:c=>3, :a=>1, :b=>2}

This, as you already know, doesn't work with Arrays:
irb(main):027:0> def stuff
irb(main):028:1> yield 1,2
irb(main):029:1> end
=> nil
irb(main):030:0> stuff {|a| p a}
(irb):30: warning: multiple values for a block parameter (2 for 1)
        from (irb):28
[1, 2]
=> nil

But that's being warned about, so I hope that, in the future, 'a' will be set to 1, instead of [1,2]. (...which would make the above trick work for Arrays.)

It wouldn't provide automatic "with index" functionality, as your hack does, but it seems (to me) to be the "cleanest" change to allow you to implement _with_index methods without polluting the methods list.

Sorry if this is a rehash (no pun intended) of stuff covered in the ruby-core thread.

Devin