サーチ…


前書き

ハッシュは、ユニークなキーとその値の辞書のようなコレクションです。連想配列とも呼ばれ、配列に似ていますが、配列が整数としてインデックスを使用する場合、Hashでは任意のオブジェクト型を使用できます。そのキーを参照してハッシュで新しいエントリを取得または作成します。

構文

  • {first_name: "Noel"、second_name: "Edmonds"}

  • {:first_name => "Noel"、:second_name => "Edmonds"}

  • {"ファーストネーム" => "ノエル"、 "セカンドネーム" => "エドモンズ"}

  • {first_key => first_value、second_key => second_value}

備考

ハッシュテーブルを使用して、Rubyのハッシュを値にマップします。

任意のハッシュ可能オブジェクトをキーとして使用できます。しかし、 Symbolを使用するのは非常に一般的です。なぜなら、オブジェクトの割り当てが減っているため、いくつかのRubyバージョンではより効率的です。

{ key1: "foo", key2: "baz"  }

ハッシュの作成

Rubyのハッシュは、キーを値にマッピングするハッシュテーブルを実装するオブジェクトです。 Rubyは、 {}を使ってハッシュを定義するための特定のリテラル構文をサポートしています:

my_hash = {}  # an empty hash
grades = { 'Mark' => 15, 'Jimmy' => 10, 'Jack' => 10 }

ハッシュは、標準的newメソッドを使用して作成することもできます。

my_hash = Hash.new  # any empty hash
my_hash = {}        # any empty hash

ハッシュは、配列、オブジェクト、その他のハッシュのような複雑な型を含むあらゆる型の値を持つことができます:

mapping = { 'Mark' => 15, 'Jimmy' => [3,4], 'Nika' => {'a' => 3, 'b' => 5} }
mapping['Mark']   # => 15
mapping['Jimmy']  # => [3, 4]
mapping['Nika']   # => {"a"=>3, "b"=>5}

また、複雑なものも含め、どのような種類のキーでも構いません:

mapping = { 'Mark' => 15, 5 => 10, [1, 2] => 9 }
mapping['Mark']  # => 15
mapping[[1, 2]]  # => 9

シンボルは一般にハッシュキーとして使用され、Ruby 1.9はこのプロセスを短縮するための特別な構文を導入しました。次のハッシュは同等です:

# Valid on all Ruby versions
grades = { :Mark => 15, :Jimmy => 10, :Jack => 10 }
# Valid in Ruby version 1.9+
grades = { Mark: 15, Jimmy: 10, Jack: 10 }

すべてのキーが文字列であるため、次のハッシュ(すべてのRubyバージョンで有効)は異なります。

grades = { "Mark" => 15, "Jimmy" => 10, "Jack" => 10 }

両方の構文バージョンを混在させることができますが、以下は推奨されません。

mapping = { :length => 45, width: 10 }

Ruby 2.2以降では、シンボルキーでハッシュを作成するための代替構文があります(シンボルにスペースが含まれている場合に最も便利です)。

grades = { "Jimmy Choo": 10, :"Jack Sparrow": 10 }
# => { :"Jimmy Choo" => 10, :"Jack Sparrow" => 10}

値へのアクセス

[][]=メソッドを使用して、ハッシュの個々の値を読み書きします。

my_hash = { length: 4, width: 5 }

my_hash[:length] #=> => 4

my_hash[:height] = 9

my_hash #=> {:length => 4, :width => 5, :height => 9 }

デフォルトでは、ハッシュに追加されていないキーにアクセスするとnilが返されます。つまり、キーの値を検索することは常に安全です。

my_hash = {}

my_hash[:age] # => nil

ハッシュには、文字列にキーを含めることもできます。それらに通常アクセスしようとすると、単にnil返されます。代わりに文字列キーでアクセスします:

my_hash = { "name" => "user" }

my_hash[:name]    # => nil
my_hash["name"]   # => user

キーが存在する必要がある、または存在する必要がある状況の場合、ハッシュにはfetchメソッドがあります。これは、存在しないキーにアクセスするときに例外を発生させます。

my_hash = {}

my_hash.fetch(:age) #=> KeyError: key not found: :age

fetchは、キーが以前に設定されていない場合に返される第2引数としてデフォルト値を受け取ります。

my_hash =  {}
my_hash.fetch(:age, 45) #=> => 45

fetchは、キーが以前に設定されていない場合に返されるブロックを受け入れることもできます:

my_hash = {}
my_hash.fetch(:age) { 21 } #=> 21

my_hash.fetch(:age) do |k|
  puts "Could not find #{k}"
end

#=> Could not find age

ハッシュは[]=エイリアスとしてstoreメソッドもサポートしています:

my_hash = {}

my_hash.store(:age, 45)

my_hash #=> { :age => 45 }

valuesメソッドを使用して、ハッシュのすべての値を取得することもできvalues

my_hash = { length: 4, width: 5 }

my_hash.values #=> [4, 5]

注:これはRuby 2.3以降の #dig のみです#digはネストしたHash便利です。 idxオブジェクトのシーケンスで指定されたネストされた値を各ステップでdigを呼び出し、中間ステップがnilの場合はnilを返すことによって抽出します。

h = { foo: {bar: {baz: 1}}}

h.dig(:foo, :bar, :baz)   # => 1
h.dig(:foo, :zot, :xyz)   # => nil

g = { foo: [10, 11, 12] }
g.dig(:foo, 1)            # => 11

デフォルト値の設定

デフォルトでは、存在しないキーの値を参照しようとするとnilが返されます。ハッシュが存在しないキーでアクセスされたときに返す値(または取るべきアクション)を指定することもできます。これは「デフォルト値」と呼ばれますが、単一の値である必要はありません。例えば、キーの長さなどの計算値であってもよい。

ハッシュのデフォルト値はそのコンストラクタに渡すことができます:

h = Hash.new(0)

h[:hi] = 1 
puts h[:hi]  # => 1 
puts h[:bye] # => 0 returns default value instead of nil

すでに構築されているHashにもデフォルトを指定することができます:

my_hash = { human: 2, animal: 1 }
my_hash.default = 0
my_hash[:plant] # => 0

新しいキーにアクセスするたびにデフォルト値がコピーされないことに注意することが重要です 。これは、デフォルト値が参照タイプの場合に驚くべき結果につながる可能性があります。

# Use an empty array as the default value
authors = Hash.new([])

# Append a book title 
authors[:homer] << 'The Odyssey'

# All new keys map to a reference to the same array:
authors[:plato] # => ['The Odyssey']

この問題を回避するために、Hashコンストラクタは、新しいキーにアクセスするたびに実行されるブロックを受け入れ、その戻り値がデフォルトとして使用されます。

authors = Hash.new { [] }

# Note that we're using += instead of <<, see below
authors[:homer] += ['The Odyssey']
authors[:plato] # => []

authors # => {:homer=>["The Odyssey"]}

上記の例では、デフォルト値が自動的にハッシュに割り当てられないため、<<の代わりに+ =を使用する必要があります。 <<を使用すると配列に追加されますが、authors [:homer]は未定義のままです:

authors[:homer] << 'The Odyssey' # ['The Odyssey']
authors[:homer] # => []
authors # => {}

アクセス時にデフォルト値を割り当てたり、より洗練されたデフォルト値を計算したりできるようにするため、デフォルトブロックはハッシュとキーの両方に渡されます。

authors = Hash.new { |hash, key| hash[key] = [] }

authors[:homer] << 'The Odyssey'
authors[:plato] # => []

authors # => {:homer=>["The Odyssey"], :plato=>[]}

デフォルトのブロックを使用して、アクションを実行したり、キー(またはその他のデータ)に依存する値を返すこともできます。

chars = Hash.new { |hash,key| key.length }

chars[:test] # => 4

より複雑なハッシュを作成することもできます。

page_views = Hash.new { |hash, key| hash[key] = { count: 0, url: key } }
page_views["http://example.com"][:count] += 1
page_views # => {"http://example.com"=>{:count=>1, :url=>"http://example.com"}}

既存のハッシュのデフォルト値をProcに設定するには、 default_proc=使用します。

authors = {}
authors.default_proc = proc { [] }

authors[:homer] += ['The Odyssey']
authors[:plato] # => []

authors # {:homer=>["The Odyssey"]}

ディープハッシュを自動的に作成する

ハッシュは、要求されたが存在しないキー(nil)のデフォルト値を持っています:

a = {}
p a[ :b ] # => nil 

新しいHashを作成するときに、デフォルトを指定することができます:

b = Hash.new 'puppy'
p b[ :b ]            # => 'puppy'

Hash.newもブロックをとります。これにより、Perlの自動化動作やmkdir -pなどのネストされたハッシュを自動的に作成できます。

# h is the hash you're creating, and k the key.
#
hash = Hash.new { |h, k| h[k] = Hash.new &h.default_proc }
hash[ :a ][ :b ][ :c ] = 3

p hash # => { a: { b: { c: 3 } } }

キーと値の変更

キーや値を変更して新しいハッシュを作成することもできます。実際には、 注射 (AKA、 reduce )を使用してキーを追加または削除することもできます。たとえば、文字列化されたキーと大文字の値を持つハッシュを生成するには:

fruit = { name: 'apple', color: 'green', shape: 'round' }
# => {:name=>"apple", :color=>"green", :shape=>"round"}

new_fruit = fruit.inject({}) { |memo, (k,v)| memo[k.to_s] = v.upcase; memo }

# => new_fruit is {"name"=>"APPLE", "color"=>"GREEN", "shape"=>"ROUND"}

ハッシュは列挙型であり、本質的にはキーと値のペアの集合です。したがって、 eachメソッド、 mapinjectなどがあります。

ハッシュのすべてのキー/値のペアについて、与えられたブロックが評価されます。最初の実行時のメモの値は、 injectために渡されたシード値です。この場合、空のハッシュ{}です。後続の評価のためのmemo値は、前のブロック評価の戻り値です。これは、キーで値を設定してmemoを変更し、最後にmemoを返す理由です。最終ブロック評価の戻り値は、私たちのケースmemo injectの戻り値です。

最終的な値を提供する必要がないようにするには、代わりにeach_with_objectを使用します。

new_fruit = fruit.each_with_object({}) { |(k,v), memo| memo[k.to_s] = v.upcase }

またはマップする

1.8
new_fruit = Hash[fruit.map{ |k,v| [k.to_s, v.upcase] }]

(ハッシュを適切に操作する方法など、詳細については、 この回答を参照してください)。

ハッシュを繰り返す

Hash含まEnumerable次のようないくつかの反復方法、提供モジュール、 Enumerable#eachEnumerable#each_pairEnumerable#each_key 、およびEnumerable#each_value

.each.each_pairは各キーと値のペアを繰り返します:

h = { "first_name" => "John", "last_name" => "Doe" }
h.each do |key, value|
    puts "#{key} = #{value}"
end

# => first_name = John
#    last_name = Doe

.each_keyはキーだけを反復します:

h = { "first_name" => "John", "last_name" => "Doe" }
h.each_key do |key|
  puts key
end

# => first_name
#    last_name

.each_valueは値だけを繰り返し処理します:

h = { "first_name" => "John", "last_name" => "Doe" }
h.each_value do |value|
    puts value
end

# => John
#    Doe

.each_with_indexは要素を反復処理し、反復のインデックスを提供します。

h = { "first_name" => "John", "last_name" => "Doe" }
h.each_with_index do |(key, value), index|
    puts "index: #{index} | key: #{key} | value: #{value}"
end

# => index: 0 | key: first_name | value: John
#    index: 1 | key: last_name | value: Doe

配列への変換と配列からの変換

ハッシュは配列間で自由に変換できます。キー/値のペアのハッシュを配列に変換すると、ペアのネストされた配列を含む配列が生成されます。

{ :a => 1, :b => 2 }.to_a # => [[:a, 1], [:b, 2]]

反対方向では、同じフォーマットの配列からハッシュを作成することができます:

[[:x, 3], [:y, 4]].to_h # => { :x => 3, :y => 4 }

同様に、ハッシュは、 Hash[]と交互のキーと値のリストを使用して初期化することができます:

Hash[:a, 1, :b, 2] # => { :a => 1, :b => 2 }

または、それぞれ2つの値を持つ配列の配列から:

Hash[ [[:x, 3], [:y, 4]] ] # => { :x => 3, :y => 4 }

ハッシュは、 flatten()を使用して、交互のキーと値の配列に変換することができます。

{ :a => 1, :b => 2 }.flatten # => [:a, 1, :b, 2]

配列への簡単な変換により、 Hashcollectzipなどの多くのEnumerableメソッドでうまく動作しEnumerable

Hash[('a'..'z').collect{ |c| [c, c.upcase] }] # => { 'a' => 'A', 'b' => 'B', ... }

people = ['Alice', 'Bob', 'Eve']
height = [5.7, 6.0, 4.9]
Hash[people.zip(height)] # => { 'Alice' => 5.7, 'Bob' => '6.0', 'Eve' => 4.9 }

すべてのキーまたはハッシュ値の取得

{foo: 'bar', biz: 'baz'}.keys   # => [:foo, :biz]
{foo: 'bar', biz: 'baz'}.values # => ["bar", "baz"]
{foo: 'bar', biz: 'baz'}.to_a   # => [[:foo, "bar"], [:biz, "baz"]]
{foo: 'bar', biz: 'baz'}.each   #<Enumerator: {:foo=>"bar", :biz=>"baz"}:each>

ハッシュ関数のオーバーライド

Rubyのハッシュはhasheql?のメソッドを使用しますeql?ハッシュ操作を実行し、ハッシュに格納されたオブジェクトを内部ハッシュ・ビンに割り当てることができます。 Rubyでのhashのデフォルトの実装は、ハッシュされたオブジェクトのすべてのメンバーフィールドに対する 雑音ハッシュ関数 です 。この動作をオーバーライドするには、 hasheql?をオーバーライドすることは可能eql?メソッド。

他のハッシュ実装と同様に、2つのオブジェクトaとbは、 a.hash == b.hash場合は同じバケットにハッシュされ、 a.eql?(b)場合は同一とみなされます。したがって、 hasheql?再実装するときはeql? abeql?下で等しいかどうかを確認するために注意が必要eql?同じhash値を返す必要があります。そうしないと、ハッシュに重複したエントリが作成される可能性があります。逆に、 hash実装の選択肢が悪いと、多くのオブジェクトが同じハッシュバケットを共有し、O(1)ルックアップ時間を効果的に破棄し、 eql?を呼び出すためにO(n)を引き起こす可能性がありeql?すべてのオブジェクトに適用されます。

次の例では、最初に追加されたクラスAのインスタンスのみがキーとして格納されます。

class A
  def initialize(hash_value)
    @hash_value = hash_value
  end
  def hash
    @hash_value # Return the value given externally
  end
  def eql?(b)
    self.hash == b.hash
  end
end

class B < A
end

a = A.new(1)
b = B.new(1)

h = {}
h[a] = 1
h[b] = 2

raise "error" unless h.size == 1
raise "error" unless h.include? b
raise "error" unless h.include? a

ハッシュをフィルタリングする

selectは、ブロックがtrue評価するキーと値のペアを持つ新しいhashを返しtrue

{ :a => 1, :b => 2, :c => 3 }.select { |k, v| k != :a && v.even? } # => { :b => 2 }

フィルタブロックでキー値を必要としない場合は、その場所で_を使用するのが一般的です。

{ :a => 1, :b => 2, :c => 3 }.select { |_, v| v.even? } # => { :b => 2 }
{ :a => 1, :b => 2, :c => 3 }.select { |k, _| k == :c } # => { :c => 3 }

rejectは、ブロックがfalse評価するキーと値のペアを持つ新しいhashを返します。

{ :a => 1, :b => 2, :c => 3 }.reject { |_, v| v.even? } # => { :a => 1, :c => 3 }
{ :a => 1, :b => 2, :c => 3 }.reject { |k, _| k == :b } # => { :a => 1, :c => 3 }

ハッシュに対する操作を設定する

  • ハッシュの交差点

    2つのハッシュの共通部分を取得するには、値が等しい共有キーを返します。

    hash1 = { :a => 1, :b => 2 }
    hash2 = { :b => 2, :c => 3 }
    hash1.select { |k, v| (hash2.include?(k) && hash2[k] == v) } # => { :b => 2 }
    
  • ハッシュの連合(マージ):

    ハッシュのキーが一意である場合、マージする両方のハッシュでキーが発生すると、そのmergeが呼び出されたハッシュからのキーが上書きされます。

    hash1 = { :a => 1, :b => 2 }
    hash2 = { :b => 4, :c => 3 }
    
    hash1.merge(hash2) # => { :a => 1, :b => 4, :c => 3 }
    hash2.merge(hash1) # => { :b => 2, :c => 3, :a => 1 }
    


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow