はじめに
こんにちは株式会社TOKOSのナオキです!
今回はRubyのdig
メソッドについて解説をしていきます。
この記事では以下の内容について取り上げています。
dig
メソッドの概要dig
メソッドの基本的な使用方法map
、compact
メソッドと組み合わせた使用方法filter_map
メソッドの使用方法
- Ruby初学者の方
- ネストされた配列やハッシュで冗長な
nil
チェックを減らしたいと思ってる方
digメソッドの概要
dig
メソッドはネストされた配列やハッシュの値を安全に取得することができます。
安全に取得とは、本来存在しない要素にアクセスをするとエラーが発生します。dig
メソッドを使用した場合、存在しない要素にアクセスしてもエラーが発生せず、nil
が返されます。
複雑なデータ構造を扱う際に、冗長なnil
チェックを記述しないでスッキリとしたコードを記述することが出来ます。
以前開発をしていた時、とあるAPIの情報を扱っていました。
その際に取得するデータが複雑にネストされたデータ構造をしていて、下記のような冗長なnil
チェックを記述していました。
data = {
user: {
profile: {
address: {
city: 'Tokyo'
}
}
}
}
# 冗長なnilチェック
if data[:user] && data[:user][:profile] && data[:user][:profile][:address]
city = data[:user][:profile][:address][:city]
else
city = nil
end
上記のような冗長なコードは可読性が良くありません。dig
メソッドを使用したら冗長なnil
チェックを記述する必要はなく、下記のようにスッキリとしたコードを記述することができます!
city = data.dig(:user, :profile, :address, :city)
基本的な使用方法
基本的な構文は下記のようになります。
data.dig(:key1, :key2, :key3, ...)
data.dig(index1, index2, index3, ...)
dig
メソッドは与えられたキーやインデックスを順番にたどり、キーやインデックス存在しない場合や途中でnil
に遭遇した場合はnil
を返します。
data = {
user: {
profile: {
name: 'Taro',
address: {
city: 'Tokyo'
}
}
}
}
name = data.dig(:user, :profile, :name)
puts name # => 'Taro'
city = data.dig(:user, :profile, :address, :city)
puts city # => 'Tokyo'
# 存在しないキーにアクセスしようとした場合nilが返る
postal_code = data.dig(:user, :profile, :address, :postal_code)
puts postal_code # => nil
animals = [['dog', 'cat',['horse', 'bird']]]
animal1 = animals.dig(0, 0)
puts animal1 # => 'dog'
animal2 = animals.dig(0, 2, 1)
puts animal2 # => 'bird'
# 存在しないインデックスにアクセスしようとした場合nilが返る
animal3 = animals.dig(0, 3)
puts animal3 # => nil
data = {
users: [
{ name: 'Naoki', details: { age: 30 } },
{ name: 'Kenta', details: { age: 25 } }
]
}
# Naokiの年齢を取得
age1 = data.dig(:users, 0, :details, :age)
puts age1 # => 30
# 存在しないデータへのアクセス
age2 = data.dig(:users, 2, :details, :age)
puts age2 # => nil
map、compactメソッドと組み合わせた使用方法
dig
メソッドとmap
、compact
メソッドを一緒に使用した応用を紹介します。
実用的だと思うのでぜひ参考にしてみてください!
users = [
{ id: 1, profile: { name: 'Naoki', age: 30 } },
{ id: 2, profile: { name: 'Kenta' } },
{ id: 3, profile: { age: 20 } },
{ id: 4, profile: nil }
]
names = users.map do |user|
user.dig(:profile, :name)
end.compact
puts names.inspect # => ['Naoki', 'Kenta']
map
メソッドは、配列の各要素に対して処理を行い、その結果を新たな配列として返します。compact
メソッドは配列内のnil
の要素を取り除きます。
上記の2つをdig
メソッドと組み合わせることで、users
配列の中で存在するname
とnilがnames
配列に格納されます。
そしてnil
の要素はcompact
によって取り除かれるので結果として、存在するname
のみがnames
配列に格納されることになります。
このように他のメソッドと組み合わせて使用することで、スッキリとした可読性の良いコードを記述することが出来ます!
map
, compact
と組み合わせた使い方を紹介しましたが、実は同じ処理をもっと簡潔に記述することが出来るメソッドがあります!
filter_mapメソッドの使用方法
上記で紹介したmap
, compact
メソッドを組み合わせた処理をfilter_map
メソッドのみで実現できます!
使用例は下記のコードになります。
users = [
{ id: 1, profile: { name: 'Naoki', age: 30 } },
{ id: 2, profile: { name: 'Kenta' } },
{ id: 3, profile: { age: 20 } },
{ id: 4, profile: nil }
]
names = users.filter_map do |user|
user.dig(:profile, :name)
end
puts names.inspect # => ['Naoki', 'Kenta']
users
に対してfilter_map
メソッドを使用することで、ブロック内の評価が真(true
)であるものだけを返します。nil
はfalse
になるので取り除かれます。
上記のように記述することでより簡潔に可読性の良いコードを記述することが出来ます!
さいごに
今回はRubyのdig
メソッドについて解説しました。
開発を行う中で、複雑にネストされたデータを扱うときも少なからずあるとおもいます。
そんなときdig
メソッドを知っているとコードをより簡潔に記述することができ、可読性を良くすることができます。
なのでネストされたデータを扱う時は積極的に使用してみてください!