2014-04-03 19 views
10

In Python è possibile leggere un dizionario/tasto hash e allo stesso tempo impostare la chiave su un valore predefinito se non esiste già.Ruby hash equivalente a Python dict setdefault

Ad esempio:

>>> d={'key': 'value'} 
>>> d.setdefault('key', 'default') 
'value'           # returns the existing value 
>>> d.setdefault('key-doesnt-exist', 'default') 
'default'          # sets and returns default value 
>>> d 
{'key-doesnt-exist': 'default', 'key': 'value'} 

Esiste un equivalente con Ruby hash? In caso negativo, qual è l'approccio idiomatico in Ruby?

risposta

8

Un Hash può avere un valore predefinito o un Proc predefinito (che viene chiamato quando una chiave è assente).

h = Hash.new("hi") 
puts h[123] #=> hi 
# change the default: 
h.default = "ho" 

Nel caso sopra l'hash rimane vuoto.

h = Hash.new{|h,k| h[k] = []} 
h[123] << "a" 
p h # =>{123=>["a"]} 

Hash.new([]) non avrebbe funzionato perché la stessa matrice (stesso come oggetto identico) potrebbe essere utilizzato per ogni tasto.

+0

+1 Stavo scrivendo questa risposta. Mi hai battuto :) –

2

Non esiste alcun equivalente a questa funzione in Python. È sempre possibile utilizzare scimmia patch per ottenere questa funzionalità:

class Hash 

    def setdefault(key, value) 
    if self[key].nil? 
     self[key] = value 
    else 
     self[key] 
    end 
    end 

end 

h = Hash.new 
h = { 'key' => 'value' } 
h.setdefault('key', 'default') 
# => 'value' 
h.setdefault('key-doesnt-exist', 'default') 
# => 'default' 

Ma tenere a mente che la scimmia patch è spesso visto come un tabù, almeno in certi ambienti di codice.

Si applica la regola d'oro del patching delle scimmie: solo perché è possibile, non significa che si dovrebbe.

Il modo più idiomatico consiste nel definire i valori predefiniti tramite Hash constructor passando un ulteriore blocco o valore.

+0

upvoted per quelli che vogliono un comportamento identico. Grazie. – gabrtv

1

Si può semplicemente pass a block to the Hash constructor:

hash = Hash.new do |hash, key| 
    hash[key] = :default 
end 

Il blocco verrà invocato quando un tentativo di accedere a una chiave inesistente è fatto. Verrà passato l'oggetto hash e la chiave. Puoi fare tutto ciò che vuoi con loro; impostare la chiave per un valore di default, ricavare un nuovo valore dalla chiave, ecc

Se si dispone già di un oggetto Hash, è possibile utilizzare the default_proc= method:

hash = { key: 'value' } 

# ... 

hash.default_proc = proc do |hash, key| 
    hash[key] = :default 
end 
+0

In genere lo vediamo scritto usando '{...}' su una singola riga, piuttosto che 'do ... end' su più righe. –

3

Non per battere un cavallo morto qui, ma setDefault si comporta più come fetch fa su un hash. Non agisce allo stesso modo di default su un hash. Una volta impostato come predefinito su un hash, qualsiasi chiave mancante utilizzerà quel valore predefinito. Questo non è il caso di setDefault. Memorizza il valore solo per la chiave mancante e solo se non riesce a trovare quella chiave. Nell'intero archivio la nuova coppia di valori chiave è diversa da quella di recupero.

Allo stesso tempo, abbiamo attualmente solo fare quello che setDefault fa in questo modo:

h = {} 
h['key'] ||= 'value' 

Rubino ha continuato a guidare il punto a casa:

h.default = "Hey now" 
h.fetch('key', 'default')      # => 'value' 
h.fetch('key-doesnt-exist', 'default')   # => 'default' 
# h => {'key' => 'value'} 
h['not your key']        # => 'Hey now' 

Python:

h = {'key':'value'} 
h.setdefault('key','default')     # => 'value' 
h.setdefault('key-doesnt-exist','default')  # => 'default' 
# h {'key': 'value', 'key-doesnt-exist': 'default'} 
h['not your key']        # => KeyError: 'not your key' 
+1

Il 'fetch' di Ruby si comporta più come Python [' get'] (https://docs.python.org/2/library/stdtypes.html#dict.get) quando gli dai un 'default' valore. il vantaggio di 'setdefault' è che * successive * linee di codice possono presumere che sia già lì e possono assumere che il' dict' non contenga chiavi diverse da quelle esplicitamente aggiunte, il che rende il codice più pulito e più facile da leggere e gestire. – jpmc26