[Feature:trunk] nested loop construct


#1

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

e$B:G6a!"e(BAO
Benche$B$r8+$F$$$^$9!#e(Bhttp://lucille.atso-net.jp/aobench/
e$B<B9T;~4V$Ne(B1/3e$B$Oe(BGCe$B$,>CHq$7$F$$$FN^L!#e(B

e$B$=$l$O$=$l$H$7$F!"e(BAO Benche$B$NCf$K$Oe(B

nphi.times do |j|
  ntheta.times do |i|

e$B$N$h$&$JB?=E%k!<%W$,$"$j$^$9!#$3$l$re(B

nloop(nphi, ntheta) do |j,i|

e$B$H$$$&$h$&$K=q$1$?$i!"$h$j$o$+$j$d$9$/!"$+$D!"$d$d9bB.$J$N$Ge(B
e$B$O$J$$$+$H9M$($^$7$?!#<B:]$K<BAu$7$?$H$3$m!"e(BAO
Benche$B$G$Oe(B5%e$BDxe(B
e$BEY<B9T;~4V$,C;=L$5$l$k$h$&$G$9!#e(B

e$B8!F$;v9`$Oe(B

  • e$B$=$b$=$bI,MW$J$N$+!#e(BYARVe$B$G$O$d$d%V%m%C%/8F$S=P$7$,=E$$79e(B
    e$B8~$,$"$k$N$G8z2L$,$"$C$?$,!"$h$j%V%m%C%/8F$S=P$7$,7ZNL$Ke(B
    e$B$J$l$PITMW$G$O$J$$$+e(B

  • e$BL>A0!#:#2s$Oe(Bnested
    loope$B$H$$$&$3$H$Ge(Bnloope$B$H$$$&L>A0$G<BAue(B
    e$B$7$?$,!"$b$C$HE,@Z$JL>A0$,$"$k$+$b$7$l$J$$!#L/$JC;=L7A$he(B
    e$B$j$bD9$/$F$b5-=RE*$JL>A0$r9%$?M$bB?$$$+$b!#e(BRuby(e$B$H$$$&$+e(B e$B;de(B)e$B$OA0<T$r9%$798~$O$"$k$1$Ie(B

e$BB>$N0F$H$7$F$Oe(Bloope$B$,0z?t$r<h$k$h$&$K$7$F!“e(Bnloope$BAjEv$K$9e(B
e$B$k$H$$$&$b$N$,$”$k!#$7$+$7!"e(B1.9e$B$Ne(Bloope$B%a%=%C%I$,;}$De(B
StopIteratione$BNc30$G%k!<%W=N;$H$$$&%;%^%s%F%#%C%/%9$HB?e(B
e$B=E%k!<%W$,$&$^$/$D$J$,$i$J$+$C$?$N$G!":#2s$O$d$a$F$
$$$?e(B

e$B$J$I$,9M$($i$l$^$9!#$I$&;W$$$^$9$+!)e(B

                            e$B$^$D$b$He(B e$B$f$-$R$me(B /:|)

#2

e$B!!$5$5$@$G$9!%e(B

Yukihiro M. wrote::

e$B:G6a!"e(BAO Benche$B$r8+$F$$$^$9!#e(Bhttp://lucille.atso-net.jp/aobench/
e$B<B9T;~4V$Ne(B1/3e$B$Oe(BGCe$B$,>CHq$7$F$$$FN^L!#e(B

e$B!!$=$3$G!$e(BFlonum e$B:GE,2=$re(B…e$B!%e(B

e$B!!$"$H!$%$%s%9%?%s%9JQ?t$N%-%c%C%7%e$rMQ$$$?:GE,2=$7$F$M!<$8$c$s!$$H:G6ae(B
e$B;XE&$5$l$?$N$G!$6aF|Cf$K$d$m$&$H;W$$$^$9!%e(B

e$B$O$J$$$+$H9M$($^$7$?!#<B:]$K<BAu$7$?$H$3$m!"e(BAO Benche$B$G$Oe(B5%e$BDxe(B
e$BEY<B9T;~4V$,C;=L$5$l$k$h$&$G$9!#e(B

e$B!!$3$&$$$&%Q%?!<%s$,B?$/$"$k$N$J$i!$$$$$$s$G$J$$$G$7$g$&$+!%$G$b!$B.EY$Ne(B
e$B$?$a$K!$$C$F$N$O$"$s$^$je(B Ruby
e$BE*$8$c$J$$$h$&$J5$$,$7$^$9!J$H$+26$,8@$&e(B
e$B$J$C$F46$8$G$9$+!K!%e(B

  • e$B$=$b$=$bI,MW$J$N$+!#e(BYARVe$B$G$O$d$d%V%m%C%/8F$S=P$7$,=E$$79e(B
    e$B8~$,$"$k$N$G8z2L$,$"$C$?$,!"$h$j%V%m%C%/8F$S=P$7$,7ZNL$Ke(B
    e$B$J$l$PITMW$G$O$J$$$+e(B

e$B!!$b$&$A$g$C$H7Z$/$J$k$h$&$K$7$?$$$H;W$&$s$G$9$,$M$’!%$"$H!$$3$&$$$&$N$Oe(B
C e$B$G=q$/$h$j$be(B Ruby e$B$G=q$$$?J}$,B.$$$+$b!%e(B

e$B$"$H!$e(B[ruby-dev:38058] e$B$KJV;v2<$5$$!%e(B


#3

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:38081] Re: [Feature:trunk] nested loop
construct”
on Thu, 26 Feb 2009 03:43:31 +0900, SASADA Koichi removed_email_address@domain.invalid
writes:

|e$B!!$=$3$G!$e(BFlonum e$B:GE,2=$re(B…e$B!%e(B

e$B40@.EY$,9b$1$l$PH?BP$O$7$^$;$s!#$G$b<+J,$G$d$k$N$O!";d$N<j$Ke(B
e$B$OIi$($^$;$s!#$I$&$;;H$C$F$k$N$Oe(Blong=64bite$B$G$J$$%^%7%s$@$7!#e(B

|e$B!!$"$H!$%$%s%9%?%s%9JQ?t$N%-%c%C%7%e$rMQ$$$?:GE,2=$7$F$M!<$8$c$s!$$H:G6ae(B
|e$B;XE&$5$l$?$N$G!$6aF|Cf$K$d$m$&$H;W$$$^$9!%e(B

e$B4|BT$7$F$^$9!#e(B

|> nloop(nphi, ntheta) do |j,i|
|>
|> e$B$H$$$&$h$&$K=q$1$?$i!"$h$j$o$+$j$d$9$/!"$+$D!"$d$d9bB.$J$N$Ge(B
|> e$B$O$J$$$+$H9M$($^$7$?!#<B:]$K<BAu$7$?$H$3$m!“e(BAO Benche$B$G$Oe(B5%e$BDxe(B
|> e$BEY<B9T;~4V$,C;=L$5$l$k$h$&$G$9!#e(B
|
|e$B!!$3$&$$$&%Q%?!<%s$,B?$/$”$k$N$J$i!$$$$$$s$G$J$$$G$7$g$&$+!%e(B

AO Benche$B$N$h$&$J2hA|7O$@$H7k9=$"$j$=$&$J5$$,$7$^$9!#IaCJ$=$Ne(B
e$B7O$N%W%m%0%i%_%s%0$K1o$,$J$$$s$G<+?.$O$J$$$G$9$,!#e(B

|e$B$G$b!$B.EY$Ne(B
|e$B$?$a$K!$$C$F$N$O$"$s$^$je(B Ruby e$BE*$8$c$J$$$h$&$J5$$,$7$^$9!J$H$+26$,8@$&e(B
|e$B$J$C$F46$8$G$9$+!K!%e(B

e$BB.EY$@$1$N$?$a$J$i$=$&$J$s$G$9$,!“0l1~$o$+$j$d$9$=$&$J5$$,$9e(B
e$B$k$H$$$&$N$b$”$k$s$G!#e(B

|> * e$B$=$b$=$bI,MW$J$N$+!#e(BYARVe$B$G$O$d$d%V%m%C%/8F$S=P$7$,=E$$79e(B
|> e$B8~$,$"$k$N$G8z2L$,$"$C$?$,!"$h$j%V%m%C%/8F$S=P$7$,7ZNL$Ke(B
|> e$B$J$l$PITMW$G$O$J$$$+e(B
|
|e$B!!$b$&$A$g$C$H7Z$/$J$k$h$&$K$7$?$$$H;W$&$s$G$9$,$M$’!%$"$H!$$3$&$$$&$N$Oe(B
|C e$B$G=q$/$h$j$be(B Ruby e$B$G=q$$$?J}$,B.$$$+$b!%e(B

e$B$=$&$+!#$A$g$C$H$d$C$F$_$h$&!#e(B

|# e$B$"$H!$e(B[ruby-dev:38058] e$B$KJV;v2<$5$$!%e(B

e$B$7$^$7$?!#e(B

                            e$B$^$D$b$He(B e$B$f$-$R$me(B /:|)

#4

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:38083] Re: [Feature:trunk] nested loop
construct”
on Thu, 26 Feb 2009 04:00:11 +0900, Yukihiro M.
removed_email_address@domain.invalid writes:

||e$B!!$b$&$A$g$C$H7Z$/$J$k$h$&$K$7$?$$$H;W$&$s$G$9$,$M$’!%$"$H!$$3$&$$$&$N$Oe(B
||C e$B$G=q$/$h$j$be(B Ruby e$B$G=q$$$?J}$,B.$$$+$b!%e(B
|
|e$B$=$&$+!#$A$g$C$H$d$C$F$_$h$&!#e(B

e$B$d$C$F$_$^$7$?!#;DG0$J$,$ie(B50%e$B$/$i$$CY$/$J$C$F%*%j%8%J%k$h$je(B
e$B$bDcB.$G$7$?!#e(B

e$B%*%j%8%J%ke(B: 262e$BICe(B
nloop(Ce$BHGe(B): 249e$BICe(B
nloop(Ruby): 375e$BICe(B

e$B%V%m%C%/8F$S=P$7$Oe(BRubye$B$+$i$NJ}$,B.$$$N$G$9$,!"$=$l$h$j$b%a%=%Ce(B
e$B%I8F$S=P$7$N>/$J$5$NJ}$,8z$/$h$&$G$9!#e(BRubye$BHGe(Bnloope$B$N:n$j$,0-$$e(B
e$B$;$$$+$b$7$l$^$;$se(B

def nloop(*args, &block)
helper = ->(args, buf, offset, block) {
limit = args[offset]
if (offset+1 == args.size)
limit.times do|i|
buf[offset] = i
block.yield *buf
end
else
limit.times do|i|
buf[offset] = i
helper.(args, buf, offset+1, block)
end
end
}
helper.(args, [], 0, block)
end


#5

Yukihiro M. wrote::

    buf[offset] = i
    helper.(args, buf, offset+1, block)
  end
end

}
helper.(args, [], 0, block)
end

e$B!!$&$o!<!$$O$8$a$F$_$^$7$?!%e(B -> e$B$H$+e(B .() e$B$H$+!%e(B

def nloop *args
str = ‘’
h = lambda{|i|
next “yield #{(0…i).map{|e| “v#{e}”}.join(’, ')}\n”
if args.length == 0

str << "v#{i} = 0; while v#{i} < #{args.shift}\n"
str << h.call(i+1)
str << "v#{i} = v#{i}.succ;end\n"
''

}
h.call(0)
eval(str)
end

require ‘benchmark’
max = 10000
Benchmark.bm{|x|
x.report{
max.times{|i|
max.times{|j|
}
}
}
x.report{
nloop(max, max){|i, j|
}
}
}

ruby 1.9.1p0 (2009-02-02 revision 21960) [i386-mswin32_90]
t.rb:12: warning: useless use of a variable in void context
user system total real
15.039000 0.000000 15.039000 ( 13.957000)
12.105000 0.031000 12.136000 ( 11.492000)

ruby 1.8.7 (2008-12-11 revision 20371) [i386-mswin32_90]
t.rb:12: warning: useless use of a variable in void context
user system total real
10.671000 0.016000 10.687000 ( 10.642000)
t.rb:13:in nloop': (eval):3:innloop’: no block given (LocalJumpError)
from t.rb:26:in eval' from t.rb:13:innloop’
from t.rb:26
from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:293:in measure' from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:380:inreport’
from t.rb:25
from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:177:in benchmark' from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:207:inbm’
from t.rb:18

  1. e$B$"$l!<!$e(B1.8.7 e$B$N$[$&$,e(B times{times{}}
    e$B$,B.$$!!$J$s$G!<!)e(B
  2. eval() e$B$NCf$+$ie(B yield e$B=PMh$J$$$s$@$C$1!)e(B

Debian etch/amd64

ruby 1.9.2dev (2009-02-26 trunk 22636) [x86_64-linux]
user system total real
7.840000 0.000000 7.840000 ( 7.836987)
7.900000 0.000000 7.900000 ( 7.900081)

ruby 1.8.5 (2006-08-25) [x86_64-linux]
user system total real
30.340000 12.900000 43.240000 ( 43.247637)
…/trunk/test.rb:8:in <<': can't convert nil into String (TypeError) from ../trunk/test.rb:8:innloop’
from …/trunk/test.rb:8:in call' from ../trunk/test.rb:8:innloop’
from …/trunk/test.rb:12:in call' from ../trunk/test.rb:12:innloop’
from …/trunk/test.rb:26
from /usr/lib/ruby/1.8/benchmark.rb:293:in measure' from /usr/lib/ruby/1.8/benchmark.rb:377:inreport’
from …/trunk/test.rb:25
from /usr/lib/ruby/1.8/benchmark.rb:177:in benchmark' from /usr/lib/ruby/1.8/benchmark.rb:207:inbm’
from …/trunk/test.rb:18

  1. 1.9 e$B$G$be(B times{times{}} e$B$N$[$&$,B.$$!]!%$J$s$G!<!)e(B
  2. 1.8.7 e$B$H%P%C%/%H%l!<%9$,0c$&!]!%e(B

#6

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:38085] Re: [Feature:trunk] nested loop
construct”
on Thu, 26 Feb 2009 05:16:41 +0900, SASADA Koichi removed_email_address@domain.invalid
writes:

|ruby 1.9.1p0 (2009-02-02 revision 21960) [i386-mswin32_90]
|t.rb:12: warning: useless use of a variable in void context
| user system total real
| 15.039000 0.000000 15.039000 ( 13.957000)
| 12.105000 0.031000 12.136000 ( 11.492000)

e$B<j85$G<B9T$7$?$i$3$s$J46$8$G$7$?!#e(B

ruby 1.9.2dev (2009-02-25 trunk 22621) [i686-linux]
user system total real
8.920000 0.020000 8.940000 ( 9.038252) # while
9.440000 0.000000 9.440000 ( 9.791861) # Ce$BHGe(B
10.270000 0.010000 10.280000 ( 10.388291) # e$B$5$5$@HGe(B
43.400000 0.080000 43.480000 ( 43.973651) # e$B$^$D$b$HHGe(B

e$B4X?tE*%W%m%0%i%_%s%0CY$9$.!#$5$i$KN^L!#e(B

|ruby 1.8.7 (2008-12-11 revision 20371) [i386-mswin32_90]
|t.rb:12: warning: useless use of a variable in void context
| user system total real
| 10.671000 0.016000 10.687000 ( 10.642000)
|t.rb:13:in nloop': (eval):3:innloop’: no block given (LocalJumpError)
| from t.rb:26:in eval' | from t.rb:13:innloop’
| from t.rb:26
| from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:293:in measure' | from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:380:inreport’
| from t.rb:25
| from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:177:in benchmark' | from c:/tmp/ruby_1_8/lib/ruby/1.8/benchmark.rb:207:inbm’
| from t.rb:18
|
|1. e$B$"$l!<!$e(B1.8.7 e$B$N$[$&$,e(B times{times{}} e$B$,B.$$!!$J$s$G!<!)e(B

e$B$J$s$G$G$7$g$&!)e(B

|2. eval() e$B$NCf$+$ie(B yield e$B=PMh$J$$$s$@$C$1!)e(B

e$B$G$-$k$O$:$G$9!#e(B

def doo
eval(“yield 42”)
end
doo{|x| p x} # => 42

e$B$J$s$G$@$m$&!#e(Bevale$B$NCf$G$5$i$Ke(Bevale$B$9$k$+$i!)e(B

                            e$B$^$D$b$He(B e$B$f$-$R$me(B /:|)

#7

Yuguie$B$G$9!#e(B

On 2/26/09 3:33 AM, Yukihiro M. wrote:

e$B8!F$;v9`$Oe(B

  • e$BL>A0!#:#2s$Oe(Bnested loope$B$H$$$&$3$H$Ge(Bnloope$B$H$$$&L>A0$G<BAue(B
    e$B$7$?$,!"$b$C$HE,@Z$JL>A0$,$"$k$+$b$7$l$J$$!#L/$JC;=L7A$he(B
    e$B$j$bD9$/$F$b5-=RE*$JL>A0$r9%$?M$bB?$$$+$b!#e(BRuby(e$B$H$$$&$+e(B e$B;de(B)e$B$OA0<T$r9%$798~$O$"$k$1$Ie(B

Array#producte$B$,%+%k%F%7%"%s@Q$J$N$G!"$=$l$K9g$o$;$Fe(BEnumerator#producte$B$Ge(B

nphi.product(ntheta).each {} e$B$de(B
(nphi * ntheta).each {}

e$B$H$$$&$N$O$I$&$G$9$+e(B?e$B!!Hs>o$KD>46E*$@$H46$8$^$9!#e(B


#8

e$B?\F#$G$9!#e(B

In removed_email_address@domain.invalid
“[ruby-dev:38095] Re: [Feature:trunk] nested loop construct” on Thu,
26 Feb 2009 17:18:15 +0900,
“Akinori MUSHA” removed_email_address@domain.invalid wrote:

v.product(*vs)

e$B$H!V<g!W$rN)$F$J$$$H$$$1$J$$$N$,$I$&$b5$$KF~$i$J$$$s$G$9$h$M!#e(B

e$B!VBP>]$H$9$ke(Bve$BA4BN!W$,!V<g!W$C$]$$5$$,$9$k$N$G!"e(B
[v1, v2, v3].product
e$B$,$$$$$J$!$H;W$$$^$7$?!#e(B


#9

At Thu, 26 Feb 2009 14:52:05 +0900,
Yugui wrote:

On 2/26/09 3:33 AM, Yukihiro M. wrote:

æ¤œè¨Žäº‹é …ã¯

  • 名前。今回はnested loopということでnloopという名前で実装
    したが、もっと適切な名前があるかもしれない。妙な短縮形よ
    りも長くても記述的な名前を好む人も多いかも。Ruby(というか
    私)は前者を好む傾向はあるけど

Array#productがカルテシアン積なので、それに合わせてEnumerator#productで

nphi.product(ntheta).each {} ã‚„

 インスタンスメソッド形式は、(Array#zip 等でも感じることですが)
3つ以上あるときに、本来対等な関係にも関わらず

v1.product(v2, v3)

とか

v, *vs = *vectors
v.product(*vs)

と「主」を立てないといけないのがどうも気に入らないんですよね。

 その点、こちらは記法としては美しいと思います:

(nphi * ntheta).each {}

しかし、 Enumerable の演算子とするのは現実的に不可能(Array#* 等と
衝突する)なので、結局は各オペランドを to_enum (each) してから演算
せざるを得ず、演算するため(だけ)にわざわざ変換するというのはやや
ä½¿ã„å‹æ‰‹ã«æ¬ ã‘ã‚‹å°è±¡ãŒã‚ã‚Šã¾ã™ã€‚

 Enumerator のクラスメソッドで実装するのはどうでしょうか。

class << Enumerator
def product(*enums)
return to_enum(method, *enums) unless block_given?

return nil if enums.empty?

e, *es = *enums

if es.empty?
  e.each { |x|
    yield [x]
  }
else
  e.each { |x|
    product(*es) { |xs|
      yield [x, *xs]
    }
  }
end

nil

end

alias nest product
end

Enumerator.nest(1…3, ‘a’…‘c’, [true, false]) { |x|
p x
}

 もし簡潔さにこだわるなら、 {Class,Module}#* は今後ないだろうと
見切って alias * product してしまえば

Enumerator.*(1…3, ‘a’…‘c’, [true, false]) { |x|
p x
}

と書けますね…。

 ただ、演算子を導入し始めると、類推や一貫性への期待から次々と
新しい提案がなされ、利便性と理論的整合性の間で苦しみ続けることに
なるのではないかという懸念も持っています。
(cf. Feature #709 [ruby-core:19681])

 なお、他に思いついたクラスメソッドは

Enumerator.transpose (synchronize)
Enumerator.join (<< or +)

などです。(前者は generator ライブラリの SyncEnumerator と同等)


#10

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:38094] Re: [Feature:trunk] nested loop
construct”
on Thu, 26 Feb 2009 14:52:05 +0900, “Yugui (Yuki S.)”
removed_email_address@domain.invalid writes:

|Array#producte$B$,%+%k%F%7%"%s@Q$J$N$G!"$=$l$K9g$o$;$Fe(BEnumerator#producte$B$Ge(B
|
|nphi.product(ntheta).each {} e$B$de(B
|(nphi * ntheta).each {}
|
|e$B$H$$$&$N$O$I$&$G$9$+e(B?e$B!!Hs>o$KD>46E*$@$H46$8$^$9!#e(B

e$B;d$,%$%a!<%8$7$F$$$?$N$OC1=c$JB?=E%k!<%W$J$N$G!“e(Bproducte$B$H$+G[e(B
e$BNs$N@Q$H$+$O!”$`$7$m$d$j$?$$$3$H$H$N5wN%$,1s$$5$$,$7$^$9!#$^e(B
e$B$?!"%+%k%F%7%"%s@Q$rF3F~$9$k$N$G$"$l$P!"e(BVectore$B$H$+$N$h$&$JJLe(B
e$B$N%/%i%9$,K>$^$7$$$h$&$J5$$,$7$^$9!#e(BEnumeratore$B$KI,MW$J5$$O$"e(B
e$B$s$^$j$7$^$;$s!#e(B