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

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

ただいまの
回答率

90.45%

  • Ruby

    9711questions

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

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

解決済

回答 5

投稿

  • 評価
  • クリップ 1
  • VIEW 1,620

yuuum

score 9

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

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

該当のソースコード

num_array = Array.new
answer_array = Array.new
width = [1,2,3]
height = [4,6,8]

height.each{|a|
    width.each{|b|
        num_array.push(a + b)
    }
    answer_array.push(num_array)
    num_array.clear
}

print answer_array

問題点

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

試したこと

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オンライン実行環境より実施

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+4

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

a = Array.new # 新しく配列を作り、それを今から a と呼ぶ。
a[0] = "hoge" # aと言う物(先ほど作った配列のこと)のインデックス番号0は、"hoge"という文字列を指すことにする。
a.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を使った方が良い場合があります。

width = [1,2,3]
height = [4,6,8]

answer_array = height.map do |a|
  width.map do |b|
    a + b
  end
end

print answer_array

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/22 07:52

    勉強になります。

    キャンセル

  • 2016/12/24 19:58

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

    キャンセル

+2

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

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

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

answer_array = Array.new
width = [1,2,3]
height = [4,6,8]

height.each{|a|
    num_array = Array.new

    width.each{|b|
        num_array.push(a + b)
    }
    answer_array.push(num_array)
}

print answer_array

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/24 20:01

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

    キャンセル

+1

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/24 20:00

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

    キャンセル

+1

width = [1,2,3]
height = [4,6,8]
answer = []
height.each do |y|
  width.each do |x|
    answer << x + y
  end
end
p 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様のプログラムを参考に私のプログラムを修正。

プログラム

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


結果

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/12/24 19:59

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

    キャンセル

0

3つの方法を示します。

x.rb

require 'matrix'

width = [1, 2, 3]
height = [4, 6, 8, 9]

p height.map { |h| width.map { |w| w + h } }
p height.product(width).map { |v| v.inject(:+) }.each_slice(width.size).to_a
p 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/30 00:59

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

    キャンセル

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

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Ruby

    9711questions

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