Rubyでは- 2 つの Enumerator をエレガントに比較すると、
zip の問題は、渡した Enumerable に関係なく、内部で配列を作成することです。入力パラメータの長さには別の問題があります
YARV での Enumerable#zip の実装を調べたところ、
static VALUE
enum_zip(int argc, VALUE *argv, VALUE obj)
{
int i;
ID conv;
NODE *memo;
VALUE result = Qnil;
VALUE args = rb_ary_new4(argc, argv);
int allary = TRUE;
argv = RARRAY_PTR(args);
for (i=0; i<argc; i++) {
VALUE ary = rb_check_array_type(argv[i]);
if (NIL_P(ary)) {
allary = FALSE;
break;
}
argv[i] = ary;
}
if (!allary) {
CONST_ID(conv, "to_enum");
for (i=0; i<argc; i++) {
argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
}
}
if (!rb_block_given_p()) {
result = rb_ary_new();
}
/* use NODE_DOT2 as memo(v, v, -) */
memo = rb_node_newnode(NODE_DOT2, result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
}
次のビットを正しく理解していますか?
すべての引数が配列であるかどうかを確認し、そうである場合は、配列への間接参照を直接参照に置き換えます
for (i=0; i<argc; i++) {
VALUE ary = rb_check_array_type(argv[i]);
if (NIL_P(ary)) {
allary = FALSE;
break;
}
argv[i] = ary;
}
すべてが配列でない場合は、代わりに列挙子を作成します
if (!allary) {
CONST_ID(conv, "to_enum");
for (i=0; i<argc; i++) {
argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each));
}
}
ブロックが指定されていない場合にのみ、配列の配列を作成します
if (!rb_block_given_p()) {
result = rb_ary_new();
}
すべてが配列の場合は を使用しzip_ary
、それ以外の場合は を使用しzip_i
、値の各セットでブロックを呼び出します
/* use NODE_DOT2 as memo(v, v, -) */
memo = rb_node_newnode(NODE_DOT2, result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
ブロックが指定されていない場合は配列の配列を返します。それ以外の場合は nil ( Qnil
) を返しますか?
return result;
}