質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

Q&A

解決済

1回答

694閲覧

[ruby] 再帰関数を用いた配列への要素の追加

aruto

総合スコア175

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

0グッド

0クリップ

投稿2019/01/06 15:02

編集2019/01/06 15:38

前提・実現したいこと

rubyを用いて競技プログラミングのような問題を解いています。
再帰関数の中で配列に要素を追加しています。
このときにarray.pushを用いると求めている結果と異なってしまいます。

該当のソースコード

問題の内容は関係ないのですが、簡略化したものを載せます。
・2次元の座標を上下左右のみ指定回数動く。
・同じ場所は通れない。
・12回移動するとき全部で何通りあるか。

ruby

1# num:動く回数, hist:動いた履歴, :cur_pos:現在の場所 2def move(num, hist = [], cur_pos = [0, 0]) 3 hist = [*hist, cur_pos] #これは動く 4 # hist.push(cur_pos) #これは動かない 5 return 0 if hist.count > num + 1 6 return 1 if hist.count == num + 1 7 8 around = [[0, 1], [0, -1], [1, 0], [-1, 0]] 9 10 around.reduce(0) do |acc, ar| 11 next_pos = [cur_pos[0] + ar[0], cur_pos[1] + ar[1]] 12 hist.include?(next_pos) ? acc : acc + move(num, hist, next_pos) 13 end 14end 15 16puts move(12)

試したこと

pushを用いずに配列に追加した場合は期待通りの結果となります。
なぜpushの場合は違うのでしょうか。
参照渡しであることが影響しているのかなとは思うのですがよくわかりません。
また、このコードの中で修正したほうが良い書き方(リファクタリング)があれば教えていただきたいです。

よろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

ruby v2.5.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

hist = [*hist, cur_pos]だと、新しいオブジェクトを作る、つまり、再帰呼び出しの階層ごとに違うオブジェクトになります。
hist.push(cur_pos)だと、同じオブジェクトに追加していく、つまり、再帰呼び出しの全ての階層で同じオブジェクトになります。

投稿2019/01/06 15:17

otn

総合スコア84529

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aruto

2019/01/06 15:36 編集

ご回答ありがとうございます。 "ローカル変数を更新する"という認識でコードを書いていたのですが hist = [*hist, cur_pos]の場合は仮引数のhistを更新したのではなく、新しくhistというオブジェクトが作られる hist.push(cur_pos)の場合は仮引数のhistがグローバル変数になる という解釈であっていますでしょうか。 また後者についてなのですが、同名の変数があった場合ローカル変数が優先されるわけではないのでしょうか。
otn

2019/01/06 15:45

hist = [*hist, cur_pos] は、新しいオブジェクトを作って、それでローカル変数のhistを更新します。 hist.push(cur_pos)は、ローカル変数が指しているオブジェクトをコピーせずに更新します。グローバル変数とか関係ないです。
aruto

2019/01/07 00:59

ご返信ありがとうございます。 hist.push(cur_pos)では、次の再帰に実引数として異なるhistオブジェクトを渡しているつもりでいるが、実は同じオブジェクトを参照しているということですね。 だから、再帰全体でhistオブジェクトが共有されてしまい、期待通り動かないということですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問