2012-11-21 10 views
5

C'è un modo non distruttivo di eliminare una coppia di valori chiave da un hash?Modo non distruttivo di cancellare una chiave da un hash

Per esempio, se avete fatto

original_hash = {:foo => :bar} 
new_hash = original_hash 
new_hash = new_hash.reject{|key, _| key == :foo} 

o

original_hash = {:foo => :bar} 
new_hash = original_hash 
new_hash = new_hash.dup 
new_hash.delete(:foo) 

poi original_hash è immutato, e new_hash è cambiato, ma sono un po 'prolisso. Tuttavia, se avete fatto

original_hash = {:foo => :bar} 
new_hash = original_hash 
new_hash.delete(:foo) 

poi original_hash è cambiato, che non è quello che voglio.

C'è un unico metodo che fa ciò che voglio?

+2

'original_hash' * è * modificato nel primo esempio utilizzando' delete_if'. Inoltre, 'new_hash' nel tuo secondo esempio usando' delete' ottiene il valore associato a ': foo', cioè': bar', non l'hash stesso. –

+0

@shioyama grazie per quello! > _ < –

risposta

8

ActiveSupport fornisce un'estensione hash: Hash#except. Permette di restituire un nuovo hash tranne le chiavi specificate senza modificare l'originale.

Supponendo di aver installato la gemma active_support:

ruby-1.9.3> require 'active_support/core_ext/hash/except.rb' 
=> true 
ruby-1.9.3> a = {x: 2, y: 1, z: 3} 
=> {:x=>2, :y=>1, :z=>3} 
ruby-1.9.3> b = a.except(:x) 
=> {:y=>1, :z=>3} 
ruby-1.9.3> c = a.except(:x, :y) 
=> {:z=>3} 
ruby-1.9.3> a 
=> {:x=>2, :y=>1, :z=>3} 
ruby-1.9.3> b 
=> {:y=>1, :z=>3} 
ruby-1.9.3> c 
=> {:z=>3} 
+1

Non utilizzo ActiveSupport, ma il fatto che forniscano un tale metodo è una buona prova che Ruby stesso non ha un tale metodo. –

1

Il problema è che new_hash è un riferimento a meno che tu non dica esplicitamente a Ruby di duplicare l'oggetto. Sei sulla strada giusta con dup, l'unica cosa che potrei consigliare è quello di fare

new_hash = original_hash.dup 

perché credo che sia così più esplicito su quello che stai facendo.

0

Che dire concatenare il dup per renderlo meno dettagliato?

new_hash = original_hash.dup.delete_if{|key, _| key == :foo} 
13

Sì, si vuole reject:

new_hash = original_hash.reject{|key, _| key == :foo} 
0
original_hash.clone.tap {|h| h.delete key} 

tap è senza dubbio meno goffo che dichiarare una nuova variabile, soprattutto perché è sulla stessa linea.

clone è, penso, più esplicitamente una copia flat di dup, anche se ovviamente per gli hash fa poca differenza.

+0

Anche se questo snippet di codice può risolvere la domanda, [compresa una spiegazione] (http://meta.stackexchange.com/questions/114762/explaining-entally-code-based-answers) aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro, e queste persone potrebbero non conoscere le ragioni del tuo suggerimento sul codice. – DimaSan