Perl es bastante agradable acerca de los valores por defecto:¿Puedo crear una matriz en Ruby con valores predeterminados?
: [email protected]; perl -e '@foo; printf "%d\n", $foo[123]'
0
: [email protected]; perl -e '%foo; printf "%d\n", $foo{bar}'
0
Ruby puede hacer lo mismo, al menos para los hashes:
>> foo = Hash.new(0)
=> {}
>> foo[:bar]
=> 0
pero el mismo aparentemente no funciona para matrices:
>> foo = Array.new(0)
=> []
>> foo[123]
=> nil
>> foo[124] = 0
=> 0
>> foo[456] = 0
=> 0
>> foo[455,456]
=> [nil, 0]
¿Es posible proporcionar un valor predeterminado para las matrices, por lo que cuando se amplían automáticamente, se rellenan con 0 en lugar de cero?
Por supuesto que puedo solucionar este problema, pero a un costo de expresividad:
>> 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.+
Actualización 1: Uno de mis colegas señalaron que puedo usar #compact
para resolver el problema #inject
y #to_i
para resolver el problema estándar elemento al índice:
>> 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]
actualización 2: Gracias aAndrew Grimm para una solución 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]
Actualización 3: esto está empezando a parecerse a golpe-a-mole!
>> foo
=> [nil, nil, nil, nil, 123]
>> foo[-2..-1]
TypeError: can't convert Range into Integer
Pero podemos lidiar con eso:
>> 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]
ahora tengo que admitir (con timidez) que voy a subclase Array
para evitar que saturan mi código:
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
Gracias por todas las soluciones creativas. TIMTOWTDI de hecho!
Si necesita una matriz dispersa, ¿qué hay de malo con el uso de un hash con claves enteras? – Simon
Me pregunto si los desarrolladores de PHP se han quejado de que su estructura de datos matriz/hash no existe en Ruby. –
Simon: Primero fui con un hash, pero me duelen algunos de los #maps y #injects que necesito hacer. –