はじめに
多次元配列にデータを格納するときの注意点を残します
今回の背景
以下の2つのransack検索結果から、[[名前, 会社名], [名前, 会社名], [名前, 会社名]]ような1つの配列を作成したい
Product.preload(:company).
ransack(name_cont_any: keywords, company_id_not_null: true).
result.
order(:name).
map(&method(:format_option))
Product.preload(:company).
ransack(company_name_cont_any: keywords, company_id_not_null: true).
result.
order(:name).
map(&method(:format_option))
間違えたこと
単純に配列に追加して最後にflattenで揃えようとしていた
product_list = IprProductReport.preload(:company).
ransack(name_cont_any: keywords, company_id_not_null: true).
result.
order(:name).
map(&method(:format_option))
product_list << IprProductReport.preload(:company).
ransack(company_name_cont_any: keywords, company_id_not_null: true).
result.
order(:name).
map(&method(:format_option)).
flatten
・名前検索の結果→意図した結果になっている
[["防犯カメラ", "(B社)"], ["ペットカメラ", "(C社)"]]
・会社検索の結果→意図した結果になっていない(階層がflattenによってずれている)
[["イヤホン", "(株式会社Bカメラ)", "セイコー", "(株式会社Bカメラ)", "忍者レフ", "(株式会社Bカメラ)"]]
最後にflattenすると、2つ目のransack結果が2個以上あるときに全て1つの配列になってしまう
実際に書いたコード
①それぞれのransack結果をproduct_list_nameとproduct_list_company_nameの配列に事前に格納する
②* で配列の要素を展開して1つの配列に格納するように
③.uniqで検索結果の重複を防ぐ
product_list_name = Product.preload(:company).
ransack(name_cont_any: keywords, company_id_not_null: true).
result.
order(:name).
map(&method(:format_option))
product_list_company_name = Product.preload(:company).
ransack(company_name_cont_any: keywords, company_id_not_null: true).
result.
order(:name).
map(&method(:format_option))
[*product_list_name, *product_list_company_name].uniq
最終的な出力結果
[["防犯カメラ", "(B社)"], ["ペットカメラ", "(C社)"], ["イヤホン", "(株式会社Bカメラ)"], ["セイコー", "(株式会社Bカメラ)"], ["忍者レフ", "(株式会社Bカメラ)"]]
スプラット演算子*について
配列の中身を展開して渡すことができる
array = [:a, :b] # => [:a, :b]
[*array, :d, :e] # => [:a, :b, :d, :e]
配列が空の場合も、階層がずれない
product_list_name = [["防犯カメラ", "(B社)"], ["ペットカメラ", "(C社)"]]
product_list_company_name = []
[*product_list_name, *product_list_company_name].uniq
# => [["防犯カメラ", "(B社)"], ["ペットカメラ", "(C社)"]]