ミニツクRubyというサイトで問題を解いていたところこんなのが。
演習 以下のコードがコメント部分の通りの出力となるように、「clever_print」メソッドの定義を書いてください。
clever_print(["Ruby"], "the", ["Programming", "Language"])
#=> Ruby the Programming Language
clever_print(["Agile", "Web", "Development"], "with", { :Rails => 3.0 })
#=> Agile Web Development with Rails 3.0
http://www.minituku.net/courses/500228005/contents/762982128.html
方針としては配列、文字列、ハッシュを引数にとり、それto_aでArrayに変換して共通の配列オブジェクトにまとめ出力するようにすれば良さそうです。
これの模範解答がRuby1.n(?)時代の解答なんです。
def clever_print(*args)
converted = []
args.each { |arg| converted << arg.to_a }
puts converted.join(' ')
end
clever_print(%w[hoge foo], 'with', fuga:1)
#=> NoMethodError: undefined method `to_a' for "with":String
Ruby2.4を想定して(配列%wしたりhashの書き方を見ていただくと)引数を記述すると、String#to_aメソッドが存在しないので怒られます。
余談ですけど、繰り返し文内でブロック変数のargをargsにすると…
def clever_print(*args)
converted = []
args.each { |arg| converted << args.to_a }
puts converted.join(' ')
end
clever_print(%w[hoge foo], 'with', fuga: 1)
#=> hoge foo with {:fuga=>1} hoge foo with {:fuga=>1} hoge foo with {:fuga=>1}
…余談でした
今風に書くとこうなる。
# frozen_string_literal: true
def method(*args)
arr = []
args.map! do |arg|
if arg.instance_of?(Hash)
arg.each do |k, v|
arr << k
arr << v
end
elsif arg.instance_of?(Array)
arg.each do |v|
arr << v
end
else
arr << arg
end
end
puts arr.join(' ')
end
method(%w[hoge foo], 'with', fuga: 1)
#=> hoge foo with fuga 1
map
はcollect
でも良いです
Object#instance_of?
により引数がHashの場合はkeyとvalueを予め用意した配列に格納、Arrayの場合
はvalueを格納、文字列の場合はそのまま文字列を格納。
少し冗長になってしまいますがシンプルにかけます。