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

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

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

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

Q&A

解決済

5回答

3946閲覧

Rubyでpushメソッド、eachメソッドを用いて多次元配列を作る

yuuum

総合スコア13

Ruby

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

1グッド

1クリップ

投稿2016/12/21 15:53

###Rubyでpushメソッド、eachメソッドを用いて多次元配列を作る
表題の通りですが、以下の3つの整数が要素として代入された配列a、配列bが2つあります。
配列a、bに含まれる各要素の和を配列aの「足される数」単位で区切りたいと考えております。
配列aをeachメソッドで繰り返し処理を行う中で、配列bのeachメソッドを繰り返し処理を行うことで各要素の和を生成し他次元配列にすることで実現できると考えたのですが、以下のコードですと想定通りの動作はしないようです。
※百ます計算の様なイメージです
※既に同じような質問がありましたらすいません。一通り洗ったつもりでしたが。

###該当のソースコード

Ruby

1num_array = Array.new 2answer_array = Array.new 3width = [1,2,3] 4height = [4,6,8] 5 6height.each{|a| 7 width.each{|b| 8 num_array.push(a + b) 9 } 10 answer_array.push(num_array) 11 num_array.clear 12} 13 14print answer_array 15

###問題点

出力が[[], [], []]となってしまいます

###試したこと
num_array.clearがある事が原因かと思い、削除してみると
[[5, 6, 7, 7, 8, 9, 9, 10, 11], [5, 6, 7, 7, 8, 9, 9, 10, 11], [5, 6, 7, 7, 8, 9, 9, 10, 11]]
との出力になります。

###補足情報(言語/FW/ツール等のバージョンなど)
ver:ruby 2.3.3
paizaオンライン実行環境より実施

raccy👍を押しています

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

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

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

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

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

guest

回答5

0

ベストアンサー

Rubyの配列はオブジェクトの入れ物では無く、オブジェクトに対する参照の入れ物です。別の言い方をすると番号で名前を付けているとも言えます。これは変数についても同じです。

Ruby

1a = Array.new # 新しく配列を作り、それを今から a と呼ぶ。 2a[0] = "hoge" # aと言う物(先ほど作った配列のこと)のインデックス番号0は、"hoge"という文字列を指すことにする。 3a.push("fuga") # aと言う物(先ほど作った配列のこと)の最後に枠を作って(この場合はインデックス番号1)、"fuga"という文字列を指すことにする。

では該当のソースコードですが、まず、num_array = Array.newで新しい配列を作っていますが、それにnum_arrayという名前をつけた事を意味します。そこで、answer_array.push(num_array)はどうなるかというと、answer_arrayの最後に枠を追加してその番号はnum_arrayと名前を付けた最初の配列をさすということです。つまり、新たに名前が足されただけで、配列自身がコピーして配列の中に入ったわけでは無いと言うことです。例えると、太郎君に社員番号0番を割り振った、と言った類のもので、太郎君が指す実体も社員番号0番が指す実体も同一人物になります。

eachの中でanswer_array.push(num_array)は三回呼ばれることになりますが、この間、num_arrayが指し示す物は変更されていませんので、同じ配列に複数の番号を付けただけになってしまいます。太郎君が社員番号0番と社員番号1番と社員番号2番の三つの番号で呼ばれるようになったような物です。

そして、num_array.clearでnum_arrayが指すもの自体を空にしています。太郎君がおなかをすかしたような物です。そうなると、社員番号0番も空腹ですし、社員番号1番も空腹ですし、社員番号2番も空腹です。みんな実体は太郎君なんですから。

解決方法はeachのループ内で配列を作ることです。echaの中にnum_array = Array.newを入れれば、その度に新たに配列が作られますので、それぞれが指す先は別の配列になります。ループの度に新入社員が入ってきて、そいつを毎回太郎君と呼んでいるような物です。ですが、これらの太郎君は毎回別の人物ですので、社員番号0番と社員番号1番と社員番号2番はそれぞれ別人になります。(実際に修正したコードはNeightさんの回答を参考にしてください。)


【おまけ】

配列または配列もどきを使って配列を作る場合はmapを使った方が良い場合があります。

Ruby

1width = [1,2,3] 2height = [4,6,8] 3 4answer_array = height.map do |a| 5 width.map do |b| 6 a + b 7 end 8end 9 10print answer_array

投稿2016/12/21 22:00

編集2016/12/21 22:04
raccy

総合スコア21735

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

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

退会済みユーザー

退会済みユーザー

2016/12/21 22:52

勉強になります。
yuuum

2016/12/24 10:58

大変参考になりました。また分かり辛い質問なのに汲み取っていただき本当にありがとうございます。本当に分かりやすかったです!
guest

0

値が参照渡し(共有渡し)になっているためでしょう

詳しい説明については下記を参照すると良いと思います。
Rubyの破壊的メソッドと参照の値渡し

かんたんな解決策としては下記のように改変します。

Ruby

1answer_array = Array.new 2width = [1,2,3] 3height = [4,6,8] 4 5height.each{|a| 6 num_array = Array.new 7 8 width.each{|b| 9 num_array.push(a + b) 10 } 11 answer_array.push(num_array) 12} 13 14print answer_array

投稿2016/12/21 16:19

Neight

総合スコア127

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

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

yuuum

2016/12/24 11:01

「Rubyの破壊的メソッドと参照の値渡し」こちらの質問も参考にさせていただきました。 該当する質問すらも自分で探せておらず、すいません。本当にありがとうございあmす!
guest

0

Ruby

1width = [1,2,3] 2height = [4,6,8] 3answer = [] 4height.each do |y| 5 width.each do |x| 6 answer << x + y 7 end 8end 9p answer.each_slice(width.length).to_a

結果

[[5, 6, 7], [7, 8, 9], [9, 10, 11]]

Neight様の出力結果を参考に同じ結果になるプログラムを考えてみました。
heightとwidthの値を順番に足してarrayに入れて
最期にarrayをwidthの要素の数で分割しています。

2016/12/22
raccy様のプログラムを参考に私のプログラムを修正。

プログラム

Ruby

1width = [1,2,3] 2height = [4,6,8] 3p height.map{|b| width.map{|a| a + b}}

結果

[[5, 6, 7], [7, 8, 9], [9, 10, 11]]

投稿2016/12/21 17:13

編集2016/12/21 23:04
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

yuuum

2016/12/24 10:59

h_aさまのご回答も本当に分かりやすく参考になりました。大変勉強になります。ありがとうございました!
guest

0

よくわかりませんが、こういうことですか?

ruby

1answer = height.map do |a| 2 width.map { |b| a + b } 3end

投稿2016/12/21 16:28

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

yuuum

2016/12/24 11:00

分かり辛い質問を汲み取っていただき本当にありがとうございます。 書いてくださあったコードをいじってみてそれっぽいものができました。ありがとうございます!
guest

0

3つの方法を示します。

x.rb

ruby

1require 'matrix' 2 3width = [1, 2, 3] 4height = [4, 6, 8, 9] 5 6p height.map { |h| width.map { |w| w + h } } 7p height.product(width).map { |v| v.inject(:+) }.each_slice(width.size).to_a 8p Matrix.build(height.size, width.size) { |h, w| height[h] + width[w] }.to_a

実行結果

$ ruby x.rb [[5, 6, 7], [7, 8, 9], [9, 10, 11], [10, 11, 12]] [[5, 6, 7], [7, 8, 9], [9, 10, 11], [10, 11, 12]] [[5, 6, 7], [7, 8, 9], [9, 10, 11], [10, 11, 12]]

投稿2016/12/29 13:17

編集2016/12/29 13:18
katoy

総合スコア22324

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

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

yuuum

2016/12/29 15:59

ありがとうございます!大変コンンパクトで見やすいです!参考にさせていただきます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問