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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

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

Q&A

解決済

2回答

1210閲覧

Railsでテーブルのカラム値をユニークかつマージしたい

kozica

総合スコア58

Ruby

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

0グッド

0クリップ

投稿2018/08/06 06:33

編集2018/08/07 02:54

personal_logsテーブルの"macaddr"カラムにMACアドレスが格納、"data"カラムに個人情報がハッシュとして格納されています
dataカラムには下記のような形の値が格納されております
{"uid":"xxxxxx","email":"xxx@xxx","phone":"xxx-xxxx-xxxx"}

ここで問題があり、"macaddr"カラムと"data"カラムには一部重複したものもあります
そこでユニークかつマージされたものにしたいです

MACアドレスがKey、dataがValuになっているハッシュに格納されている配列を下記のようなものにしたとします
(ただし、下記は指摘をうけ、正しくない形となっています)

ruby

1[{"32:5A:3D:87:21:AA" =>"{"uid":"dfasdfas","email":"apple@gmail.com"}", 2 "32:5A:3D:87:21:AA" =>"{"uid":"kdjfasdf","email":"apple@gmail.com"}", 3 "32:5A:3D:87:21:AA" =>"{"email":"bunana@gmail.com","phone":"080-4345-xx23"}", 4 "43:76:4A:DD:2C:BB" =>"{"uid":"dfjaskdi","email":"orenge@gamil.com","phone":"090-4649-77xx"}", 5 "43:76:4A:DD:2C:BB" =>"{"phone":"090-4649-77xx","email":"remon@gamil.com"}", 6 ........."":"{}"}]

dataにはKeyとして'uid''email''phone'が入っています
上記の配列で、MACアドレスがユニーク、dataがユニークかつマージされた配列に変更したいです。

下記のような形にしたいです

[{"32:5A:3D:87:21:AA" =>"{"uid":"dfasdfas,kdjfasdf","email":"apple@gmail.com,bunana@gmail.com","phone":"080-4345-xx23"}", "43:76:4A:DD:2C:BB" =>"{"uid":"dfjaskdi","email":"orenge@gamil.com,remon@gmail.com","phone":"090-4649-77xx"}", ........."":"{}"}]

結果的に、私は上記のようなユニークかつマージされた形にしたく思っています

rails:5.2.0
ruby:2.5.1

###回答を受けて追記
回答のコードをrails console上で実行したところ下記エラーになってしました、、、

ruby

1a = Array.new 2sample = PersonalLog.all 3sample.find_each do |x| 4 hash = Hash.new 5 hash[x.macaddr] = x.decrypted_data 6 a.push(hash) 7end 8 9# aの中身を一部抜粋 10# a = [{"70:DD:23"=>"{\"uid\":\"6729661\",\"email\":\"orenge@gmail.com\"}"}, 11# {"70:E7:AA"=>"{\"uid\":\"3014134\"}"}, 12# {"00:18"=>"{\"uid\":\"1040\"}"}, 13# ,,,,,{"DD:23:32"=>"{\"email\":\"apple@docomo.ne.jp\"}"}] 14 15 16irb(main):009:0> new_data = a.each_with_object(Hash.new{|h, k|h[k] = Hash.new}){|it, memo| 17irb(main):010:1* it.each{|mac, val| 18irb(main):011:2* memo[mac].merge!(val){|_,s,o| s + ',' + o} 19irb(main):012:2> } 20irb(main):013:1> } 21Traceback (most recent call last): 22 7: from (irb):9 23 6: from (irb):9:in `each_with_object' 24 5: from (irb):9:in `each' 25 4: from (irb):10:in `block in irb_binding' 26 3: from (irb):10:in `each' 27 2: from (irb):11:in `block (2 levels) in irb_binding' 28 1: from (irb):11:in `merge!' 29TypeError (no implicit conversion of String into Hash)

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

テストする時面倒くさいからデータを記述するならRubyで読める形式にしてほしいです。
(ユーザー定義クラスとか混じらなければ、単純にpメソッドで出力されたテキストだと楽です)

ruby

1data = [ 2{"32:5A:3D:87:21:AA" =>{"uid":"dfasdfas","email":"apple@gmail.com"}}, 3{"32:5A:3D:87:21:AA" =>{"uid":"kdjfasdf","email":"apple@gmail.com"}}, 4{"32:5A:3D:87:21:AA" =>{"email":"bunana@gmail.com","phone":"080-4345-xx23"}}, 5{"43:76:4A:DD:2C:BB" =>{"uid":"dfjaskdi","email":"orenge@gamil.com","phone":"090-4649-77xx"}}, 6{"43:76:4A:DD:2C:BB" =>{"phone":"090-4649-77xx","email":"remon@gamil.com"}}, 7] 8new_data = data.each_with_object(Hash.new{|h, k|h[k] = Hash.new}){|it, memo| 9 it.each{|mac, val| 10 memo[mac].merge!(val){|_,s,o| s + ',' + o} 11 } 12} 13new_data.transform_values!{|val| val.transform_values{|v| v.split(',').uniq.join(',')}} 14pp new_data 15# => {"32:5A:3D:87:21:AA"=> 16# {:uid=>"dfasdfas,kdjfasdf", 17# :email=>"apple@gmail.com,bunana@gmail.com", 18# :phone=>"080-4345-xx23"}, 19# "43:76:4A:DD:2C:BB"=> 20# {:uid=>"dfjaskdi", 21# :email=>"orenge@gamil.com,remon@gamil.com", 22# :phone=>"090-4649-77xx"}} 23# 普通、このまま使った方が楽 24 25pp new_data.keys.map{|k| {k => new_data[k]}} 26# => [{"32:5A:3D:87:21:AA"=> 27# {:uid=>"dfasdfas,kdjfasdf", 28# :email=>"apple@gmail.com,bunana@gmail.com", 29# :phone=>"080-4345-xx23"}}, 30# {"43:76:4A:DD:2C:BB"=> 31# {:uid=>"dfjaskdi", 32# :email=>"orenge@gamil.com,remon@gamil.com", 33# :phone=>"090-4649-77xx"}}]

投稿2018/08/06 08:20

編集2018/08/06 08:43
asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kozica

2018/08/06 08:26

上記内容だと同じキー(uid、email、phone)に対しての値が上書きされていないでしょうか? 同じキーで値が違う場合は追記する形にしたいです。 例)"uid" : "kdjfasdf, dfasdfas"
kazto

2018/08/06 08:42

each_with_object便利っすねぇ!
asm

2018/08/06 08:46

> kozicaさん 失礼しました。 追記かつユニークになるように編集しておきました > kaztoさん reduce/injectとブロック引数の順番逆になるということを覚えとく必要があるけど便利ですね
kozica

2018/08/06 09:02 編集

ご丁寧にありがとうございます。 初歩的で申し訳ないのですが、上記のdata配列の作成でこけてしまってます 私は下記のように書いてみましたがだめでした、、、 sample = PersonalLog.all sample.each do |x| a = Array.new h = Hash.new h["x.macaddr"] = x.data a.push(h) end
kozica

2018/08/06 09:06 編集

あ、a,hの定義をeachの外に出してうまくいきました!
kozica

2018/08/07 02:55 編集

回答のコードを実行したところエラーが出てしましました。 投稿の方にエラー内容を記載致しました aの中身を見てみると\(バックスラッシュ)が所々に入っていたのでこれが原因なのでしょうか?
kozica

2018/08/07 05:03 編集

JSON.parse(x.decrypted) にすることで上記内容は解決致しました。 しかし、次は下記でエラーになりました irb(main):019:0> new_data.transform_values!{|val| val.transform_values{|v| v.split(',').uniq.join(',')}} Traceback (most recent call last): 5: from (irb):19 4: from (irb):19:in `transform_values!' 3: from (irb):19:in `block in irb_binding' 2: from (irb):19:in `transform_values' 1: from (irb):19:in `block (2 levels) in irb_binding' NoMethodError (undefined method `split' for 3196917654:Integer) splitがエラーで出ているようです。
guest

0

Ruby

1["32:5A:3D:87:21:AA" =>"{"uid":"dfasdfas","email":"apple@gmail.com"}", 2 "32:5A:3D:87:21:AA" =>"{"uid":"kdjfasdf","email":"apple@gmail.com"}", 3 "32:5A:3D:87:21:AA" =>"{"email":"bunana@gmail.com","phone":"080-4345-xx23"}",

上記の表現は配列、ハッシュの表現がごちゃまぜになっており、意図したデータになっていないと思われます。
=>で連結されたデータはハッシュとなりますが、[]で囲われているので、正確には以下のようになります。

Ruby

1[{"32:5A:3D:87:21:AA" =>"{"email":"bunana@gmail.com","phone":"080-4345-xx23"}", 2 ... 3 }]

すみません、キーが同じだったですね。。。
この場合、警告が出るとともに、最後のキーのみ有効になります。

連結文字を「:」にしても同じことです。
頭で考えた形式ではなく、実際に存在しているデータを示していただけると、より回答しやすくなると思います。
(CSVファイルだったりしますでしょうか?)


入力データの形式が判明したため、追記します。

以下のように愚直に連結するしかないかなーと思います。

Ruby

1sample = PersonalLog.all 2h = {} 3sample.each do |x| 4 h2 = {} 5 x.data.each do |key, val| 6 if h2[key].nil? 7 # キーに対応する値が無ければ、そのまま値を代入する 8 h2[key] = val 9 else 10 # キーに対応する値が存在するときは、カンマで連結する 11 h2[key] = [h2[key], val].join(",") 12 end 13 end 14 h.[x.macaddr]=h2 15end

投稿2018/08/06 06:53

編集2018/08/06 08:04
kazto

総合スコア7196

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kozica

2018/08/06 07:00 編集

失礼しました ご指摘ありがとうございます 投稿を修正致しました よろしくお願い致します
kazto

2018/08/06 07:02

訂正を受けて、回答を訂正しました。
kozica

2018/08/06 07:18

投稿をもっと具体的に修正致します
kozica

2018/08/06 07:29

投稿に修正加えたとおり、railsでDBのテーブルのデータに対して行いたいです。
kazto

2018/08/06 08:04

回答を修正しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問