LoginSignup
0
0

More than 3 years have passed since last update.

【修正版】csvファイルを開いてハッシュとして取り込むメソッド

Last updated at Posted at 2021-04-30

私が未熟なためコードが動きません。

@scivolaさまのこの記事の下のコメントを元に修正させていただきました。

丁寧に見ていただけて感謝です。

addresses = []
File.open("address_book.csv").each_line do |info| #---①
a = info.split "," #---②
addresses << AddressInfo.new(*a) #---③
end.close#---④

@scivolaさま提案
require "csv"
addresses = []
CSV.foreach("address_book.csv") do |row| #---②
  addresses << AddressInfo.new(*row)     #---③
end                                      #---④

①File.open("ファイル名")(「*ファイルは必ずCSVファイルで)」は読み込みモードで指定したファイルを開き、Fileクラスのオブジェクトを返します。ここでは返されたオブジェクトはeach_lineメソッドforeach(を使って1行ずつ展開してメモリを節約します。)に利用されています。each_lineメソッドではファイルを行単位で読み込み読み込んだ行をブロック引数に格納します。
②splitメソッドはinfoブロックに格納された行単位の文をしてしたカンマごとに文字列に分割します。
③newクラスでオブジェクトを生成します。ここではアドレスに書かれたzip.code,prefecture,ward,cityなどカンマごとに分解されたものを<<で配列にして格納します。
closeメソッドで開いたファイルを閉じます。処理を終えます。(開放)

(注)「<<」の記号を使うことで配列末尾に配列要素を追加できます。

各パラメータの種類

Rubyのメソッド定義で使えるパラメータを以下の8つに分類しています。

種別
必須 a
オプション b = 2
配列分解 (c, *d)
splat *args
post-required f
キーワード g:, h: 7
ダブルsplat **kwargs
ブロック &blk
  1. 必須・・・必須パラメータは、呼び出し側で引数を与えないとエラーになるパラメータです。つまりこの「必須」は「呼び出し側で引数を省略できない」という意味になります。
def foo(a)        # aが必須パラメータ(普通のパラメータ)
  puts "a: #{a}"
end
foo     #=> エラー
  1. オプション・・・パラメータにデフォルト値を与えたものはオプションのパラメータになります。オプションなので、引数を渡さない場合はデフォルト値が使われ、エラーになりません。
def foo(a = 1)  # a = 1がオプションパラメータ(デフォルト値を持つ)
  puts "a: #{a}"
end
foo     #=> a: 1
  1. 配列分解・・・配列分解は、入れ子になった配列をリテラルで(=変数に入れずに)渡された場合に配列を部分に切り分けて受け取る、特殊な動作です。分解のパターンは、パラメータ側のsplat(後述)の配置や丸かっこ( )によって複雑に変化します。引数に[1, 2], 3を与えた場合の例を以下に示します。

(*a) # a = [1, 2], 3 # a = [1, 2], b = 3
(a, *b) # a = [1, 2], b = 3 # a = [1, 2], b = 3, c = # a = 1, b = 2, c = 3
((a, *b), c) # a = 1, b = [2], c = 3
かなり複雑ですね。パズルみたいで楽しそうですが、パラメータの数が増えると、入れ子の配列リテラルの分解を正確に理解して引数で渡すのは至難の業です。引数に配列リテラルをうかつに書くと落とし穴にハマりそうです。

def method1(*a)
  puts "a: #{a}"
end;
def method2(a, b)
  puts "a: #{a}"
  puts "b: #{b}"
end;
def method3(a, *b)
  puts "a: #{a}"
  puts "b: #{b}"
end;
def method4(a, b, *c)
  puts "a: #{a}"
  puts "b: #{b}"
  puts "c: #{c}"
end;
def method5((a, b), c)
  puts "a: #{a}"
  puts "b: #{b}"
  puts "c: #{c}"
end;
def method6((a, *b), c)
  puts "a: #{a}"
  puts "b: #{b}"
  puts "c: #{c}"
end;
method1 [1, 2], 3;      # a: [[1, 2], 3]
method2 [1, 2], 3;      # a: [1, 2], b: 3
method3 [1, 2], 3;      # a: [1, 2], b: [3]
method4 [1, 2], 3;      # a: [1, 2], b: 3, c: []
method5 [1, 2], 3;      # a: 1, b: 2, c: 3
method6 [1, 2], 3;      # a: 1, b: [2], c: 3
  1. splat・・・パラメータ文字の前に*を追加すると、長さが不定の引数リスト(可変長引数リスト)を受けられるようになります。これをsplatパラメータと呼んでいます。上の配列分解の例にも、splatパラメータが含まれているものがあります。splatパラメータは、さまざまな種類の引数をいくつ渡してもすべて受け取れます。
def foo(*a)       # *aがsplatパラメータ
  puts "a: #{a}"
end

foo :one, "two", [:three, "four"]
#=> a: [:one, "two", [:three, "four"]]
  1. post-required・・・splatパラメータの直後に置いた必須パラメータは、post-requiredパラメータとして動作します(本記事では英ママで表記します)。この場合ちょうどsplatパラメータのストッパーのような働きをし、splatパラメータに渡される引数リストの末尾の引数を受け取ります。

以下の例では、bがpost-requiredパラメータとして動作します。
```rb
def foo(*a, b) # bがpost-requiredパラメータ
puts "a: #{a}"
puts "b: #{b}"
end

foo :one, "two", {key1: "value"}, [:three, "four"]

=> a: [:one, "two", {:key1=>"value"}]

=> b: [:three, "four"]



6. キーワード・・・パラメータ名にRubyのシンボルの書式「キーワード:」を使うと、キーワード付きパラメータになります(キーワード付き引数と呼ばれることもよくあります)。

```rb
def foo(name)          # ただの必須パラメータ
  puts "name: #{name}"
end

def foo(name:)         # キーワード
  puts "name: #{name}"
end

def foo(name: "bar")   # デフォルト値付きキーワード
  puts "name: #{name}"
end

キーワード付きパラメータの最大のメリットは、メソッド呼び出し側でのキーワード付き引数の順序が不問になることです。メソッドを呼び出す側にとっては順序を気にしなくてよくなるので大変使いやすくなります。

キーワード付きパラメータにデフォルト値を与えないと引数が必須になります
引数がない場合や、またはキーワードが示されていない場合にエラーになります
デフォルト値を与えれば引数がなくてもエラーになりません
特にデフォルト値付きキーワードは、メソッド呼び出し側で{key: "value"}のようなハッシュでのオプション引数渡しと同じ感覚で、しかも順序不問でkey-valueペアのオプションを渡せるので便利です。

def foo(name: "bar", addr: "tokyo", tel: "03-9999-9999")
  puts "name: #{name}"
  puts "addr: #{addr}"
  puts "tel:  #{tel}"
end

foo(tel: "03-0000-0000", addr: "shibuya", name: "baz") # 呼び出し側で順序を気にしなくてよい
#=> name: baz
#=> addr: shibuya
#=> tel:  03-0000-0000
'''

参考
Ruby 2.0.0リリース!  キーワード引数を使ってみよう
Ruby 2.1.0リリース!注目の新機能を見てみましょう

7. ダブルsplat・・・パラメータ名の前に**を付けるとダブルsplatパラメータになります。splatパラメータと似ていますが、可変長のキーワード引数リストを受け取る前提である点が異なります。ダブルsplatは、上述のopts = {}形式のオプションパラメータと同様の動作です。

```rb
def foo(**profile)            # ダブルsplat
  puts "profile: #{profile}"
end

foo(tel: "03-0000-0000", addr: "shibuya", name: "baz")
#=> profile: {:tel=>"03-0000-0000", :addr=>"shibuya", :name=>"baz"}

なお、可変長のキーワード引数リストをダブルでないsplatパラメータで受けると、配列の中にハッシュが保存されるので取り出しに一手間余計にかかります。

def foo(*profile)              # ただのsplat
  puts "profile: #{profile}"
end

foo(tel: "03-0000-0000", addr: "shibuya", name: "baz")
#=> profile: [{:tel=>"03-0000-0000", :addr=>"shibuya", :name=>"baz"}]   <=配列の中にハッシュがある
  1. ブロック・・・最後のブロックは、他のパラメータと異なる点があります。メソッド定義でyieldでブロックを実行する場合は、パラメータに何も書かなくても、呼び出し側で引数リストの最後にブロックを置くことで渡せます(以下: 暗黙のブロックパラメータ)。逆に、パラメータの末尾に&付きのブロックパラメータを明示的に置いてブロックを受けることもできます(以下: 明示的なブロックパラメータ)。
# 暗黙
def foo              # 普通のパラメータも、ブロックを受けるパラメータもない
  yield
end

foo { puts "hello" } #=> hello

# 明示
def foo &blk         # &blkはブロック専用のパラメータ
  blk.call
end

foo { puts "hello" } #=> hello

暗黙のブロックパラメータで受けたブロックには名前がありません。

明示的なブロックパラメータで受けたブロックには名前があるので、他のメソッドにブロックを渡したりできるようになります。後編の「ブロックとproc」を参照してください。

参考: #parametersメソッド・・・Method#parametersメソッドを使うと、メソッドのパラメータリストを取得できます。取得したリストには、上で説明したパラメータの種別も含まれます。先ほどのfooメソッドに対してこのメソッドを実行すると以下の結果が得られます。

method(:foo).parameters
# [[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :g], [:block, :blk]]

参考:hachi8833さん

https://techracho.bpsinc.jp/hachi8833/2017_04_05/37930

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0