LoginSignup
8
9

More than 5 years have passed since last update.

Rubyで多次元HashやArrayから特定のキーを削除する

Last updated at Posted at 2016-10-26

Rubyで多次元HashやArrayから特定のキーを削除する

一次元のHashから特定のキーを削除したい場合は、

h = {a: 1, b: 2, c: 3}

# :bを削除
h.delete_if{|k, v| k == :b }
=>{a: 1, c: 3}

が1つの手ですが、多次元Hashの場合はどうするか。

h = {a: {aa: 1, ab: 2, ac: 3}, b: 2, c:3}

# :aaを削除したい

# NG
h.delete_if{|k, v| k == :aa }
=> {a: {aa: 1, ab: 2, ac: 3}, b: 2, c:3}

# OK
p = proc do |k, v|
  v.respond_to?(:delete_if) ? (v.delete_if(&p); nil) : k == :aa
end
h.delete_if(&p)
=> {a: {ab: 2, ac: 3}, b: 2, c:3}

条件をprocにして再帰的にdelete_ifをします。
v.respond_to?(:delete_if) 部分は、v.instance_of?(Hash) でもいいかもしれません。どれだけ階層が深くなっても対応できるはず。

ただ、HashにArrayも入ってくると上記のコードだけではまかなえないため、以下のようなコードとしました。

h = {a: [{aa: 1, ab: 2, ac: 3}, {aa: 4, ab: 5, ac: 6}], b: 2, c:3}
p = proc do |k, v|
  k.respond_to?(:delete_if) ? (k.delete_if(&p); nil) : (v.respond_to?(:delete_if) ? (v.delete_if(&p); nil) : k == :aa)
end
h.delete_if(&p)
=> {a: [{ab: 2, ac: 3}, {ab: 5, ac: 6}], b: 2, c: 3}

keyvalそれぞれにdelete_ifの存在を確認しつつ、純粋なHashであればkeyを評価する処理です。
ただ、ちょっと長ったらしい感じなので、再帰の条件がもっとシンプルにならないものかなあとは思います。

8
9
0

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
8
9