1. ホーム
  2. ruby

[解決済み] ハッシュのキーと値を入れ替える方法

2022-04-22 01:17:13

質問

Hashのキーと値を入れ替えるにはどうしたらいいですか?

次のようなHashがあります。

{:a=>:one, :b=>:two, :c=>:three}

に変換したい。

{:one=>:a, :two=>:b, :three=>:c}

使用方法 map は、かなり面倒なようです。もっと手軽な解決策はないのでしょうか?

どのように解決するのですか?

RubyにはHashのヘルパーメソッドがあり、Hashを反転させたように扱うことができます(要するに、値を通してキーにアクセスできるようにする)。

{a: 1, b: 2, c: 3}.key(1)
=> :a

反転したハッシュを維持したいのであれば ハッシュ#invert は、ほとんどの状況で動作するはずです。

{a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}

でも...

値が重複している場合。 invert は、最後に出現した値以外をすべて破棄します (反復処理中にそのキーの新しい値を置き換え続けるからです)。同様に key は最初にマッチしたものだけを返します。

{a: 1, b: 2, c: 2}.key(2)
=> :b

{a: 1, b: 2, c: 2}.invert
=> {1=>:a, 2=>:c}

したがって、値が一意である場合は、以下のように使用できます。 Hash#invert . そうでない場合は、このようにすべての値を配列として保持することができます。

class Hash
  # like invert but not lossy
  # {"one"=>1,"two"=>2, "1"=>1, "2"=>2}.inverse => {1=>["one", "1"], 2=>["two", "2"]} 
  def safe_invert
    each_with_object({}) do |(key,value),out| 
      out[value] ||= []
      out[value] << key
    end
  end
end

注:このテスト付きコードは、現在 をGitHubで公開しています。 .

または

class Hash
  def safe_invert
    self.each_with_object({}){|(k,v),o|(o[v]||=[])<<k}
  end
end