Perl è abbastanza bello su valori di default:Posso creare una matrice in Ruby con valori predefiniti?
: [email protected]; perl -e '@foo; printf "%d\n", $foo[123]'
0
: [email protected]; perl -e '%foo; printf "%d\n", $foo{bar}'
0
rubino può fare lo stesso, almeno per gli hash:
>> foo = Hash.new(0)
=> {}
>> foo[:bar]
=> 0
ma lo stesso apparentemente non funziona per gli array:
>> foo = Array.new(0)
=> []
>> foo[123]
=> nil
>> foo[124] = 0
=> 0
>> foo[456] = 0
=> 0
>> foo[455,456]
=> [nil, 0]
È possibile fornire un valore predefinito per gli array, quindi quando sono auto-estesi, vengono riempiti con 0 anziché zero?
Certo che posso ovviare a questo, ma ad un costo di espressività:
>> foo[457,458] = 890, 321
=> [890, 321]
>> foo[456] += 789
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+
>> foo.inject(0) {|sum, i| sum += (i || 0) }
=> 1211
>> foo.inject(:+)
NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.+
Update 1: Uno dei miei colleghi ha sottolineato che posso usare #compact
per risolvere il problema #inject
e #to_i
per risolvere l'elemento-at-index problema standard:
>> foo.include? nil
=> true
>> foo.compact.inject(:+)
=> 1211
>> foo[456,457]
=> [0, 890, 321]
>> foo[455..457]
=> [nil, 0, 890]
>> foo[455..457].map(&:to_i)
=> [0, 0, 890]
Aggiornamento 2: Grazie a Andrew Grimm per una soluzione al problema +=
:
>> foo = []
=> []
>> def foo.[](i)
>> fetch(i) {0}
>> end
=> nil
>> foo[4]
=> 0
>> foo
=> []
>> foo[4] += 123
=> 123
>> foo
=> [nil, nil, nil, nil, 123]
Update 3: questo sta cominciando a guardare come Whack-a-mole!
>> foo
=> [nil, nil, nil, nil, 123]
>> foo[-2..-1]
TypeError: can't convert Range into Integer
Ma possiamo fare con questo:
>> def foo.[](index)
>> if index.is_a? Range
>> index.map {|i| self[i] }
>> else
?> fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array
>> end
>> end
=> nil
>> foo
=> [nil, nil, nil, nil, 123]
>> foo[-2..-1]
=> [nil, 123]
ora devo ammettere (timidamente) che io sottoclasse Array
per evitare di ingombrare il mio codice:
class MyClass
class ArrayWithDefault < Array
def [](index)
if index.is_a? Range
index.map {|i| self[i] }
else
fetch(index) { 0 } # default to 0 if no element at index; will not cause auto-extension of array
end
end
end
end
Grazie per tutte le soluzioni creative. TIMTOWTDI davvero!
Se hai bisogno di un array sparse, cosa c'è di sbagliato nell'usare un hash con chiavi intere? – Simon
Mi chiedo se qualche sviluppatore PHP si sia lamentato del fatto che la loro struttura di dati array/hash non esiste in Ruby. –
Simon: Sono andato con un hash in primo luogo, ma c'è un problema con alcune delle #maps e #inject che devo fare. –