From: Tanaka Akira Date: 2010-03-16T17:59:48+09:00 Subject: [ruby-dev:40676] Re: Enumerable#interleave 2010年3月14日16:36 Yukihiro Matsumoto : > > 確かにzipはちょっと揺らいだことがあって、ruby-coreで議論した > ことがあります。結局、その時はレシーバーの長さ優先という結論 > を出したのですが、今思えばあまり良くなかったなあと。たとえば、 > with_indexのようなものをzipを使って作る場合、連番が先頭に来 > れないというのはかなり大きな制約のような気がします。 えぇと、たとえば 0から無限に連番を作る iota と 有限の配列 ary があったとして、 ary.each.with_index {|e,i| } は ary.zip(iota) {|e,i| } と実現できるが、 iota.zip(ary) {|i,e| } は無限ループになってしまう、という意味ですか? % ./ruby -e ' iota = Enumerator.new {|y| i = 0; loop { y << i; i += 1 } } ary = %w[a b c] ary.zip(iota) {|x,y| p [x,y] } iota.zip(ary) {|x,y| p [x,y] } ' ["a", 0] ["b", 1] ["c", 2] [0, "a"] [1, "b"] [2, "c"] [3, nil] [4, nil] [5, nil] ... でも、かなり大きな制約、というのはよくわかりません。 どうせブロック引数で受けとるなら、順番はどうにでもなるのでは? 連番を先頭に表示したければ、 ary.zip(iota) {|e,i| p [i,e] } とすれば可能ですよね。 議論をしたという [ruby-core:14738] からのスレッドを読むと、 レシーバの長さを優先するとユーザが繰り返しの終了を選べるが、 最短ので止まると選べない、という点が指摘されていて、それには共感を覚えます。 連番は先頭に置いた方がわかりやすい、というならわからないでもないですが、 その利点が、ユーザが選べるという利点を越えるとは感じません。 > 考えたのは、interlave対象に無限列を含む場合です。たとえば > with_indexをflattenしたようなものを得る時に、停止しないのは > 使いにくかろうと。 iota.interleave(ary) {|x| p x } が 0, "a", 1, "b", 2, "c", 3, 4, 5, ... となるのは使いにくい、と。 ふむ。それはそんな気がしないでもないですね。 zip とは違って、ブロック引数でどうにかすることはできませんからね。 でも、停止したとしても、それをどう使うかというのを考えると 結局は使いにくいという結論になるかもしれないとも思います。 > どうも、具体的になりきれないのがいけませんね。 そうですね。具体例があれば、その例について便利かどうかを考えられるんですが、 ここで出てきている例くらいだと、具体性が足りなくてそういうことを考えるのは 難しいです。 Hash[k1,v1,k2,v2,...] は ks = [k1,k2,...] vs = [v1,v2,...] とすると Hash[*ks.interleave(vs)] と書けて、 interleave が有用な例のような気がするんですが、 これ自体は他の方法で解決されているし、 同じような困り方をした他の例は思い出せないんだよなぁ。 -- [田中 哲][たなか あきら][Tanaka Akira]