it-swarm.com.de

Schlüssel und Werte in einem Hash austauschen

Wie kann ich in Ruby Schlüssel und Werte in einem Hash austauschen?

Nehmen wir an, ich habe den folgenden Hash:

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

Dass ich mich verwandeln möchte in:

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

Die Verwendung einer Karte scheint ziemlich langweilig zu sein. Gibt es eine kürzere Lösung?

132
Jonathan Allard

Ruby hat eine Hilfsmethode für Hash, mit der Sie einen Hash so behandeln können, als wäre er invertiert. 

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

Wenn Sie den invertierten Hash beibehalten möchten, sollte Hash # invert in den meisten Situationen funktionieren.

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

ABER...

Wenn Sie doppelte Werte haben, verwirft invert alle Werte außer den letzten. Ebenso wird key nur die erste Übereinstimmung zurückgeben. 

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

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

Wenn also Ihre Werte eindeutig sind, können Sie Hash#invert verwenden. Wenn nicht, können Sie alle Werte wie ein Array beibehalten:

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

Hinweis: Dieser Code mit Tests ist jetzt hier

Oder kurz gesagt ...

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

Sie wetten, es gibt einen! Es gibt immer einen kürzeren Weg, Dinge in Ruby zu erledigen!

Es ist ziemlich einfach, benutze einfach Hash#invert :

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

Et voilà!

60
Jonathan Allard
# this doesn't looks quite as elegant as the other solutions here,
# but if you call inverse twice, it will preserve the elements of the original hash

# true inversion of Ruby Hash / preserves all elements in original hash
# e.g. hash.inverse.inverse ~ h

class Hash

  def inverse
    i = Hash.new
    self.each_pair{ |k,v|
      if (v.class == Array)
        v.each{ |x|
          i[x] = i.has_key?(x) ? [k,i[x]].flatten : k
        }
      else
        i[v] = i.has_key?(v) ? [k,i[v]].flatten : k
      end
    }
    return i
  end

end

Hash#inverse gibt dir:

 h = {a: 1, b: 2, c: 2}
 h.inverse
  => {1=>:a, 2=>[:c, :b]}
 h.inverse.inverse
  => {:a=>1, :c=>2, :b=>2}  # order might not be preserved
 h.inverse.inverse == h
  => true                   # true-ish because order might change

während die eingebaute invert-Methode gerade kaputt ist:

 h.invert
  => {1=>:a, 2=>:c}    # FAIL
 h.invert.invert == h 
  => false             # FAIL
1
Tilo
files = {
  'Input.txt' => 'Randy',
  'Code.py' => 'Stan',
  'Output.txt' => 'Randy'
}

h = Hash.new{|h,k| h[k] = []}
files.map {|k,v| h[v]<< k}
puts h

Dadurch werden auch die doppelten Werte verarbeitet.

1
Riaze

Array verwenden

input = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4", :key5=>"value5"}
output = Hash[input.to_a.map{|m| m.reverse}]

Hash verwenden 

input = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4", :key5=>"value5"}
output = input.invert

Wenn Sie einen Hash haben, in dem die Schlüssel eindeutig sind, können Sie Hash # invert verwenden:

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

Das funktioniert jedoch nicht, wenn Sie nicht eindeutige Schlüssel haben, bei denen nur die zuletzt gesehenen Schlüssel aufbewahrt werden:

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

Wenn Sie einen Hash mit nicht eindeutigen Schlüsseln haben, können Sie Folgendes tun:

> hash={a: 1, b: 2, c: 3, d: 3, e: 2, f: 1}
> hash.each_with_object(Hash.new { |h,k| h[k]=[] }) {|(k,v), h| 
            h[v] << k
            }     
=> {1=>[:a, :f], 2=>[:b, :e], 3=>[:c, :d]}

Wenn die Werte des Hash bereits Arrays sind, können Sie Folgendes tun:

> hash={ "A" => [14, 15, 16], "B" => [17, 15], "C" => [35, 15] }
> hash.each_with_object(Hash.new { |h,k| h[k]=[] }) {|(k,v), h| 
            v.map {|t| h[t] << k}
            }   
=> {14=>["A"], 15=>["A", "B", "C"], 16=>["A"], 17=>["B"], 35=>["C"]}
0
dawg