[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: accessing index inside map

Peña, Botp

7/11/2005 1:51:00 AM

Yukihiro Matsumoto [mailto: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?

Hi sir Matz,

You're vague plan produces clearer ruby..

but isn't
each_with_index.map

so close to being
map_with_index

?

(1..6).map_with_index{|x,i|[2,5].include?(i) ? x : x*2} is very easy to my
tiny brain since all i have to remember is map (just like (in array) all i
have to focus is each, then i follow thru with each_with_index)

i'm sorry, i'm a map/collect fan so pardon my insistence :-)

thanks in advance.

kind regards
-botp -another spoiled nuby spoiled by map


#
# matz.
#


31 Answers

Yukihiro Matsumoto

7/11/2005 1:59:00 AM

0

Hi,

In message "Re: accessing index inside map"
on Mon, 11 Jul 2005 10:50:31 +0900, "Peña, Botp" <botp@delmonte-phil.com> writes:

|# (1..6).each_with_index.map{|x,i|[2,5].include?(i) ? x : x*2}
|#
|#then. It's much simpler isn't it?

|but isn't
| each_with_index.map
|
|so close to being
| map_with_index
|
|?

Yes. But when we add map_with_index, we might be asked to add
collect_with_index, detect_with_index, inject_with_index, and all
other enumerable methods _with_index as well.

matz.


Nakada, Nobuyoshi

7/11/2005 5:02:00 AM

0

Hi,

At Mon, 11 Jul 2005 10:50:31 +0900,
Peña, Botp wrote in [ruby-talk:147720]:
> You're vague plan produces clearer ruby..
>
> but isn't
> each_with_index.map
>
> so close to being
> map_with_index
>
> ?
>
> (1..6).map_with_index{|x,i|[2,5].include?(i) ? x : x*2} is very easy to my
> tiny brain since all i have to remember is map (just like (in array) all i
> have to focus is each, then i follow thru with each_with_index)

What about Enumerator#with_index?

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

--
Nobu Nakada


Ryan Leavengood

7/11/2005 5:10:00 AM

0

nobuyoshi nakada wrote:
>
> What about Enumerator#with_index?
>
> [1,2,3,4,5,6].map.with_index {|x,i|[2,5].include?(i) ? x : x*2}

I like that, personally. In fact each_with_index could become
each.with_index (though we obviously need the old one for backwards
compatibility.)

Ryan


Nakada, Nobuyoshi

7/11/2005 5:29:00 AM

0

Hi,

At Mon, 11 Jul 2005 14:09:41 +0900,
Ryan Leavengood wrote in [ruby-talk:147729]:
> > What about Enumerator#with_index?
> >
> > [1,2,3,4,5,6].map.with_index {|x,i|[2,5].include?(i) ? x : x*2}
>
> I like that, personally. In fact each_with_index could become
> each.with_index (though we obviously need the old one for backwards
> compatibility.)

Indeed.

$ ./ruby -renumerator -e 'p (1..6).to_enum.with_index{|x,i|p [x,i]}'
[1, 0]
[2, 1]
[3, 2]
[4, 3]
[5, 4]
[6, 5]
1..6

A patch based on the current implementation.


Index: ext/enumerator/enumerator.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/enumerator/enumerator.c,v
retrieving revision 1.3.2.2
diff -U2 -p -r1.3.2.2 enumerator.c
--- ext/enumerator/enumerator.c 4 Nov 2004 01:20:50 -0000 1.3.2.2
+++ ext/enumerator/enumerator.c 11 Jul 2005 05:25:15 -0000
@@ -162,4 +162,27 @@ enumerator_each(obj)
}

+static VALUE
+enumerator_with_index_i(val, memo)
+ VALUE val, *memo;
+{
+ val = rb_yield_values(2, val, INT2FIX(*memo));
+ ++*memo;
+ return val;
+}
+
+static VALUE
+enumerator_with_index(obj)
+ VALUE obj;
+{
+ VALUE memo = 0;
+
+ obj = (VALUE)rb_node_newnode(NODE_MEMO,
+ rb_ivar_get(obj, id_enum_obj),
+ rb_to_id(rb_ivar_get(obj, id_enum_method)),
+ rb_ivar_get(obj, id_enum_args));
+ return rb_iterate((VALUE (*)_((VALUE)))enumerator_iter, obj,
+ enumerator_with_index_i, (VALUE)&memo);
+}
+
void
Init_enumerator()
@@ -183,4 +206,5 @@ Init_enumerator()
rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
+ rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);

sym_each = ID2SYM(rb_intern("each"));


--
Nobu Nakada


Yukihiro Matsumoto

7/11/2005 5:57:00 AM

0

Hi,

In message "Re: accessing index inside map"
on Mon, 11 Jul 2005 14:29:24 +0900, nobuyoshi nakada <nobuyoshi.nakada@ge.com> writes:

| $ ./ruby -renumerator -e 'p (1..6).to_enum.with_index{|x,i|p [x,i]}'
| [1, 0]
| [2, 1]
| [3, 2]
| [4, 3]
| [5, 4]
| [6, 5]
| 1..6
|
|A patch based on the current implementation.

Can you commit this patch to the HEAD?

matz.


Nakada, Nobuyoshi

7/11/2005 7:42:00 AM

0

Hi,

At Mon, 11 Jul 2005 14:57:00 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:147731]:
> | $ ./ruby -renumerator -e 'p (1..6).to_enum.with_index{|x,i|p [x,i]}'
> | [1, 0]
> | [2, 1]
> | [3, 2]
> | [4, 3]
> | [5, 4]
> | [6, 5]
> | 1..6
> |
> |A patch based on the current implementation.
>
> Can you commit this patch to the HEAD?

For performance, I'd like to make Enumerator a subclass of
Data instead of Object, in the HEAD.


Index: ext/enumerator/enumerator.c
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/enumerator/enumerator.c,v
retrieving revision 1.5
diff -U2 -p -r1.5 enumerator.c
--- ext/enumerator/enumerator.c 2 Nov 2004 07:38:21 -0000 1.5
+++ ext/enumerator/enumerator.c 11 Jul 2005 07:38:27 -0000
@@ -18,5 +18,77 @@
static VALUE rb_cEnumerator;
static ID sym_each, sym_each_with_index, sym_each_slice, sym_each_cons;
-static ID id_new, id_enum_obj, id_enum_method, id_enum_args;
+#if !defined(HAVE_RB_PROC_CALL) || !defined(HAVE_RB_METHOD_CALL)
+static ID id_call;
+#endif
+
+static VALUE
+proc_call(proc, args)
+ VALUE proc, args;
+{
+#ifdef HAVE_RB_PROC_CALL
+ if (TYPE(args) != T_ARRAY) {
+ args = rb_values_new(1, args);
+ }
+ return rb_proc_call(proc, args);
+#else
+ return rb_funcall2(proc, id_call, 1, &args);
+#endif
+}
+
+static VALUE
+method_call(method, args)
+ VALUE method, args;
+{
+#ifdef HAVE_RB_METHOD_CALL
+ return rb_method_call(RARRAY(args)->len, RARRAY(args)->ptr, method);
+#else
+ return rb_funcall2(method, id_call, RARRAY(args)->len, RARRAY(args)->ptr);
+#endif
+}
+
+struct enumerator {
+ VALUE method;
+ VALUE proc;
+ VALUE args;
+ VALUE (*iter)_((VALUE, struct enumerator *));
+};
+
+static void enumerator_mark _((void *));
+static void
+enumerator_mark(p)
+ void *p;
+{
+ struct enumerator *ptr = p;
+ rb_gc_mark(ptr->method);
+ rb_gc_mark(ptr->proc);
+ rb_gc_mark(ptr->args);
+}
+
+static struct enumerator *
+enumerator_ptr(obj)
+ VALUE obj;
+{
+ struct enumerator *ptr;
+
+ Data_Get_Struct(obj, struct enumerator, ptr);
+ if (RDATA(obj)->dmark != enumerator_mark) {
+ rb_raise(rb_eTypeError,
+ "wrong argument type %s (expected Enumerable::Enumerator)",
+ rb_obj_classname(obj));
+ }
+ if (!ptr) {
+ rb_raise(rb_eArgError, "uninitialized enumerator");
+ }
+ return ptr;
+}
+
+static VALUE enumerator_iter_i _((VALUE, struct enumerator *));
+static VALUE
+enumerator_iter_i(i, e)
+ VALUE i;
+ struct enumerator *e;
+{
+ return rb_yield(proc_call(e->proc, i));
+}

static VALUE
@@ -26,5 +98,7 @@ obj_to_enum(obj, enum_args)
rb_ary_unshift(enum_args, obj);

- return rb_apply(rb_cEnumerator, id_new, enum_args);
+ return rb_class_new_instance(RARRAY(enum_args)->len,
+ RARRAY(enum_args)->ptr,
+ rb_cEnumerator);
}

@@ -33,5 +107,8 @@ enumerator_enum_with_index(obj)
VALUE obj;
{
- return rb_funcall(rb_cEnumerator, id_new, 2, obj, sym_each_with_index);
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_with_index;
+ return rb_class_new_instance(2, args, rb_cEnumerator);
}

@@ -39,8 +116,8 @@ static VALUE
each_slice_i(val, memo)
VALUE val;
- NODE *memo;
+ VALUE *memo;
{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
+ VALUE ary = memo[0];
+ long size = (long)memo[1];

rb_ary_push(ary, val);
@@ -48,5 +125,5 @@ each_slice_i(val, memo)
if (RARRAY(ary)->len == size) {
rb_yield(ary);
- memo->u1.value = rb_ary_new2(size);
+ memo[0] = rb_ary_new2(size);
}

@@ -59,14 +136,14 @@ enum_each_slice(obj, n)
{
long size = NUM2LONG(n);
- NODE *memo;
- VALUE ary;
+ VALUE args[2], ary;

if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");

- memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;

- rb_iterate(rb_each, obj, each_slice_i, (VALUE)memo);
+ rb_iterate(rb_each, obj, each_slice_i, (VALUE)args);

- ary = memo->u1.value;
+ ary = args[0];
if (RARRAY(ary)->len > 0) rb_yield(ary);

@@ -78,5 +155,9 @@ enumerator_enum_slice(obj, n)
VALUE obj, n;
{
- return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_slice, n);
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_slice;
+ args[2] = n;
+ return rb_class_new_instance(3, args, rb_cEnumerator);
}

@@ -84,8 +165,8 @@ static VALUE
each_cons_i(val, memo)
VALUE val;
- NODE *memo;
+ VALUE *memo;
{
- VALUE ary = memo->u1.value;
- long size = memo->u3.cnt;
+ VALUE ary = memo[0];
+ long size = (long)memo[1];

if (RARRAY(ary)->len == size) {
@@ -104,10 +185,11 @@ enum_each_cons(obj, n)
{
long size = NUM2LONG(n);
- NODE *memo;
+ VALUE args[2];

if (size <= 0) rb_raise(rb_eArgError, "invalid size");
- memo = rb_node_newnode(NODE_MEMO, rb_ary_new2(size), 0, size);
+ args[0] = rb_ary_new2(size);
+ args[1] = (VALUE)size;

- rb_iterate(rb_each, obj, each_cons_i, (VALUE)memo);
+ rb_iterate(rb_each, obj, each_cons_i, (VALUE)args);

return Qnil;
@@ -118,5 +200,19 @@ enumerator_enum_cons(obj, n)
VALUE obj, n;
{
- return rb_funcall(rb_cEnumerator, id_new, 3, obj, sym_each_cons, n);
+ VALUE args[2];
+ args[0] = obj;
+ args[1] = sym_each_cons;
+ args[2] = n;
+ return rb_class_new_instance(3, args, rb_cEnumerator);
+}
+
+static VALUE enumerator_allocate _((VALUE));
+static VALUE
+enumerator_allocate(klass)
+ VALUE klass;
+{
+ struct enumerator *ptr;
+ return Data_Make_Struct(rb_cEnumerator, struct enumerator,
+ enumerator_mark, -1, ptr);
}

@@ -128,4 +224,5 @@ enumerator_initialize(argc, argv, obj)
{
VALUE enum_obj, enum_method, enum_args;
+ struct enumerator *ptr = enumerator_ptr(obj);

rb_scan_args(argc, argv, "11*", &enum_obj, &enum_method, &enum_args);
@@ -134,16 +231,25 @@ enumerator_initialize(argc, argv, obj)
enum_method = sym_each;

- rb_ivar_set(obj, id_enum_obj, enum_obj);
- rb_ivar_set(obj, id_enum_method, enum_method);
- rb_ivar_set(obj, id_enum_args, enum_args);
+ ptr->method = rb_obj_method(enum_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;
+ }
+ ptr->args = enum_args;

- return Qnil;
+ return obj;
}

+static VALUE enumerator_iter _((VALUE));
static VALUE
enumerator_iter(memo)
- NODE *memo;
+ VALUE memo;
{
- return rb_apply(memo->u1.value, memo->u2.id, memo->u3.value);
+ struct enumerator *e = (struct enumerator *)memo;
+
+ return method_call(e->method, e->args);
}

@@ -152,14 +258,29 @@ enumerator_each(obj)
VALUE obj;
{
- VALUE val;
+ struct enumerator *e = enumerator_ptr(obj);

- obj = (VALUE)rb_node_newnode(NODE_MEMO,
- rb_ivar_get(obj, id_enum_obj),
- rb_to_id(rb_ivar_get(obj, id_enum_method)),
- rb_ivar_get(obj, id_enum_args));
- val = rb_iterate((VALUE (*)_((VALUE)))enumerator_iter, obj, rb_yield, 0);
+ return rb_iterate(enumerator_iter, (VALUE)e, e->iter, (VALUE)e);
+}
+
+static VALUE
+enumerator_with_index_i(val, memo)
+ VALUE val, *memo;
+{
+ val = rb_yield_values(2, val, INT2FIX(*memo));
+ ++*memo;
return val;
}

+static VALUE
+enumerator_with_index(obj)
+ VALUE obj;
+{
+ struct enumerator *e = enumerator_ptr(obj);
+ VALUE memo = 0;
+
+ return rb_iterate(enumerator_iter, (VALUE)e,
+ enumerator_with_index_i, (VALUE)&memo);
+}
+
void
Init_enumerator()
@@ -181,6 +302,8 @@ Init_enumerator()
rb_include_module(rb_cEnumerator, rb_mEnumerable);

+ rb_define_alloc_func(rb_cEnumerator, enumerator_allocate);
rb_define_method(rb_cEnumerator, "initialize", enumerator_initialize, -1);
rb_define_method(rb_cEnumerator, "each", enumerator_each, 0);
+ rb_define_method(rb_cEnumerator, "with_index", enumerator_with_index, 0);

sym_each = ID2SYM(rb_intern("each"));
@@ -189,7 +312,6 @@ Init_enumerator()
sym_each_cons = ID2SYM(rb_intern("each_cons"));

- id_new = rb_intern("new");
- id_enum_obj = rb_intern("enum_obj");
- id_enum_method = rb_intern("enum_method");
- id_enum_args = rb_intern("enum_args");
+#if !defined(HAVE_RB_PROC_CALL) || !defined(HAVE_RB_METHOD_CALL)
+ id_call = rb_intern("call");
+#endif
}
Index: ext/enumerator/extconf.rb
===================================================================
RCS file: /cvs/ruby/src/ruby/ext/enumerator/extconf.rb,v
retrieving revision 1.1
diff -U2 -p -r1.1 extconf.rb
--- ext/enumerator/extconf.rb 1 Nov 2004 05:04:04 -0000 1.1
+++ ext/enumerator/extconf.rb 23 Jun 2005 02:55:54 -0000
@@ -1,2 +1,5 @@
require 'mkmf'
+
+%w"rb_obj_method rb_method_call".all? {|f| have_func(f, "ruby.h")}
+have_func("rb_proc_call", "ruby.h")
create_makefile('enumerator')


--
Nobu Nakada


Yukihiro Matsumoto

7/11/2005 7:48:00 AM

0

Hi,

In message "Re: accessing index inside map"
on Mon, 11 Jul 2005 16:41:45 +0900, nobuyoshi nakada <nobuyoshi.nakada@ge.com> writes:

|> Can you commit this patch to the HEAD?
|
|For performance, I'd like to make Enumerator a subclass of
|Data instead of Object, in the HEAD.

It's all up to you. Although I feel no need to check rb_proc_call,
since enumerator is bundled with Ruby itself.

matz.


Nakada, Nobuyoshi

7/11/2005 8:37:00 AM

0

Hi,

At Mon, 11 Jul 2005 16:48:29 +0900,
Yukihiro Matsumoto wrote in [ruby-talk:147737]:
> |> Can you commit this patch to the HEAD?
> |
> |For performance, I'd like to make Enumerator a subclass of
> |Data instead of Object, in the HEAD.
>
> It's all up to you. Although I feel no need to check rb_proc_call,
> since enumerator is bundled with Ruby itself.

Static function proc_call() is defined now but rb_proc_call()
is not. Also rb_obj_method() and rb_method_call().

--
Nobu Nakada


Yukihiro Matsumoto

7/11/2005 9:10:00 AM

0

Hi,

In message "Re: accessing index inside map"
on Mon, 11 Jul 2005 17:37:07 +0900, nobuyoshi nakada <nobuyoshi.nakada@ge.com> writes:

|> It's all up to you. Although I feel no need to check rb_proc_call,
|> since enumerator is bundled with Ruby itself.
|
|Static function proc_call() is defined now but rb_proc_call()
|is not. Also rb_obj_method() and rb_method_call().

I know. But if you need those functions, just export (with proper
prefix). I see no need for have_func() check in extconf.rb.

matz.


dblack

7/11/2005 11:08:00 AM

0