eachでイテレーションさせているコレクションに破壊的変更を加えると
どうなるんだろうと思ったやってみたらちょっと面白かったので。
!
※破壊的メソッドを使ってもこのように命を狙われることはありません。
破壊的メソッドと非破壊的メソッド
破壊的メソッドは、新たなオブジェクトを生成して返すのではなく、メソッドを持つオブジェクト自身(レシーバ)に変更を加えて返すメソッドです*1。慣例的に、メソッド名に「!」がついているメソッドは破壊的変更をします。ついてないメソッドは必ず非破壊的メソッドなのかといえばそうでもなく、破壊的変更をするものがあります。
では早速。
push、pop、shift、unshiftしてみる
irb(main):1:0> c = (1..10).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] irb(main):2:0> c.each{|a| c.pop } => [1, 2, 3, 4, 5]
shiftだと6から10が残ります。先頭から削っていくので全部なくなると思ったらそうではないようです。また、pushまたはunshiftすると止まりません。コレクションの末尾に要素を追加していくpushが止まらないのは自明ですが、これまたunshifは止まるかなと思ったら止まりませんでした。
map!で足してみる
irb(main):3:0> c = (1..10).to_a => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] irb(main):4:0> c.each{|a| c.map!{|b| a + b } } => [2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046]
上の場合、長さn、初項1、公差dの有限等差数列ついては、初項s_(1,1) = 1, s_(n,1) = d(s_(n-1,1) + (2^n-1)-1)、公差dの等差数列ができあがります。
足し算ではなく引き算の場合は初項n-1(nが奇数)または1-n(nが偶数)、公差dの等差数列になります。末項はかならず0になるようです。
で、これ使い道あるの?
さ、さあ…
まず間違いなく普通のコーディングではやらないでしょうし、2つ目はなんかの漸化式で使えないかなと試してみたら思ったよりも微妙な挙動するし、使いどころが思いつきません。irbで実行してみて「うわーなんだこれー」と思うくらいにとどめたほうがよさそうです。
*1:Array#uniq!など特定の条件下でレシーバ自身を返さないものもある