LoginSignup
4
0

More than 1 year has passed since last update.

[Ruby] hash の配列を、その1要素を key にした hash にする

Last updated at Posted at 2022-12-11
[
  {id: 1, name: 'aaa', user_uuid: 'b43f670d-a367-8eed-e0b4-0c561b0b0d51'},
  {id: 2, name: 'bbb', user_uuid: '4070ec80-9c88-5a64-ca01-2fb25cb6c45e'},
  {id: 3, name: 'ccc', user_uuid: 'b59345bd-3cda-89cc-e1a0-793c740e1442'},
]

これを

{
  'b43f670d-a367-8eed-e0b4-0c561b0b0d51' => {id: 1, name: 'aaa', user_uuid: 'b43f670d-a367-8eed-e0b4-0c561b0b0d51'},
  '4070ec80-9c88-5a64-ca01-2fb25cb6c45e' => {id: 2, name: 'bbb', user_uuid: '4070ec80-9c88-5a64-ca01-2fb25cb6c45e'},
  'b59345bd-3cda-89cc-e1a0-793c740e1442' => {id: 3, name: 'ccc', user_uuid: 'b59345bd-3cda-89cc-e1a0-793c740e1442'},
}

こうします。

はじめに

「こっちのダッシュボードとこっちのシステムから出した CSV がそれぞれあって、user_uuid ってのでくっつくようになってるから統合して?」
という時の利用を考えています。
行の1要素のままでは使いにくいので引き出してしまおうという事ですね。

require 'csv'

csv_table = CSV.read('sample.csv', encoding: 'BOM|UTF-8', col_sep: ',', row_sep: "\n", headers: true)

csv_table.each do |row|
  p row
end
#<CSV::Row "id":"1" " name":" aaa" " user_uuid":" b43f670d-a367-8eed-e0b4-0c561b0b0d51">
#<CSV::Row "id":"2" " name":" bbb" " user_uuid":" 4070ec80-9c88-5a64-ca01-2fb25cb6c45e">
#<CSV::Row "id":"3" " name":" ccc" " user_uuid":" b59345bd-3cda-89cc-e1a0-793c740e1442">

というわけで実際は CSV::Row を想定していますが大きな違いはありません。
sample.csv の中身は冒頭の配列が出てくるような内容です。

id,name,user_uuid
1,aaa,b43f670d-a367-8eed-e0b4-0c561b0b0d51
2,bbb,4070ec80-9c88-5a64-ca01-2fb25cb6c45e
3,ccc,b59345bd-3cda-89cc-e1a0-793c740e1442

どうせ便利な使いきりタイプのコードなので何も考えず each で回して用意した空ハッシュに放り込めば終わりですが、こういう自由な時にいろいろ試しておかないと開発してるときには付け焼刃では太刀打ちできないのです。

# 適当な形
require 'csv'

csv_table = CSV.read('sample.csv', encoding: 'BOM|UTF-8', col_sep: ',', row_sep: "\n", headers: true)

hash = {}

csv_table.each do |row|
  hash[row['user_uuid']] = row
end

p hash
# {
#   "b43f670d-a367-8eed-e0b4-0c561b0b0d51"=>#<CSV::Row "id":"1" "name":"aaa" "user_uuid":"b43f670d-a367-8eed-e0b4-0c561b0b0d51">,
#   "4070ec80-9c88-5a64-ca01-2fb25cb6c45e"=>#<CSV::Row "id":"2" "name":"bbb" "user_uuid":"4070ec80-9c88-5a64-ca01-2fb25cb6c45e">,
#   "b59345bd-3cda-89cc-e1a0-793c740e1442"=>#<CSV::Row "id":"3" "name":"ccc" "user_uuid":"b59345bd-3cda-89cc-e1a0-793c740e1442">
# }

実際のコード

require 'csv'

csv_table = CSV.read('sample.csv', encoding: 'BOM|UTF-8', col_sep: ',', row_sep: "\n", headers: true)

hash = csv_table.map{|row|row['user_uuid']}.zip(csv_table).to_h

p hash

# {
#   "b43f670d-a367-8eed-e0b4-0c561b0b0d51"=>#<CSV::Row "id":"1" "name":"aaa" "user_uuid":"b43f670d-a367-8eed-e0b4-0c561b0b0d51">,
#   "4070ec80-9c88-5a64-ca01-2fb25cb6c45e"=>#<CSV::Row "id":"2" "name":"bbb" "user_uuid":"4070ec80-9c88-5a64-ca01-2fb25cb6c45e">,
#   "b59345bd-3cda-89cc-e1a0-793c740e1442"=>#<CSV::Row "id":"3" "name":"ccc" "user_uuid":"b59345bd-3cda-89cc-e1a0-793c740e1442">
# }

メソッドチェーンで呼び出せて気分がいいですね。
せっかくなのでそれぞれ順にみてみます。

map()

require 'csv'

csv_table = CSV.read('sample.csv', encoding: 'BOM|UTF-8', col_sep: ',', row_sep: "\n", headers: true)

p csv_table.map{|row|row['user_uuid']}

# ["b43f670d-a367-8eed-e0b4-0c561b0b0d51", "4070ec80-9c88-5a64-ca01-2fb25cb6c45e", "b59345bd-3cda-89cc-e1a0-793c740e1442"]

目的の値だけの配列を作成します。

zip()

require 'csv'

csv_table = CSV.read('sample.csv', encoding: 'BOM|UTF-8', col_sep: ',', row_sep: "\n", headers: true)

p csv_table.map{|row|row['user_uuid']}.zip(csv_table)

# [
#   ["b43f670d-a367-8eed-e0b4-0c561b0b0d51", #<CSV::Row "id":"1" "name":"aaa" "user_uuid":"b43f670d-a367-8eed-e0b4-0c561b0b0d51">],
#   ["4070ec80-9c88-5a64-ca01-2fb25cb6c45e", #<CSV::Row "id":"2" "name":"bbb" "user_uuid":"4070ec80-9c88-5a64-ca01-2fb25cb6c45e">],
#   ["b59345bd-3cda-89cc-e1a0-793c740e1442", #<CSV::Row "id":"3" "name":"ccc" "user_uuid":"b59345bd-3cda-89cc-e1a0-793c740e1442">]
# ]

目的の値と、その値のもとになった行の配列を作成します。

to_h()

require 'csv'

csv_table = CSV.read('sample.csv', encoding: 'BOM|UTF-8', col_sep: ',', row_sep: "\n", headers: true)

p csv_table.map{|row|row['user_uuid']}.zip(csv_table).to_h

# {
#   "b43f670d-a367-8eed-e0b4-0c561b0b0d51"=>#<CSV::Row "id":"1" "name":"aaa" "user_uuid":"b43f670d-a367-8eed-e0b4-0c561b0b0d51">,
#   "4070ec80-9c88-5a64-ca01-2fb25cb6c45e"=>#<CSV::Row "id":"2" "name":"bbb" "user_uuid":"4070ec80-9c88-5a64-ca01-2fb25cb6c45e">,
#   "b59345bd-3cda-89cc-e1a0-793c740e1442"=>#<CSV::Row "id":"3" "name":"ccc" "user_uuid":"b59345bd-3cda-89cc-e1a0-793c740e1442">
# }

最後にそれぞれを [key, value] として hash に変換します。

おわり

CSV をその内の1要素を key にした hash へ変換できました。
記事の途中で相手が配列から CSV になりましたが基本的に配列でも同じ方法を使えます。

これで受け取ったもう1つの CSV にも user_uuid が共有されていればそこで合流させていけるわけですね。
今回は私がよく使う方法を記載しましたが、もちろん他にもいろいろな手法が取れます。

RDB に取り込んだ方が早いのでは?

4
0
1

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
4
0