Piedras preciosas de Ruby
Muchas veces en programación hay que tabular una serie de datos. Lo más usual es recorrer toda la serie y contar cada elemento en una tabla.
En Java (1.5) un método de hacerlo sería así:
ArrayList<String> lista = /* una lista de palabras, por ejemplo */;
Hashmap<String, Integer> tabla = new Hashmap();
for (String palabra: lista) {
int contador;
if ((contador = tabla.get(palabra)) != null) {
// La palabra ya estaba en la tabla
tabla.put(palabra, ++contador);
} else { // La palabra no estaba en la tabla
tabla.put(palabra, 0);
}
}
Es muy simple y muy sencillo gracias principalmente a la posibilidad del bucle for each que nos permite Java 1.5 (a pesar de que tenemos que utilizar templates, que hace un poco pesado escribir las declaraciones iniciales).
En Ruby el anterior código sería similar:
lista = # una lista de palabras, por ejemplo
tabla = {}
for palabra in lista do
if (tabla[palabra])
# La palabra ya estaba en la tabla
tabla[palabra] += 1
else # La palabra no estaba en la tabla
tabla[palabra] = 0
end
end
Se podría decir que Ruby es más expresivo y que Java más académico (cada uno tiene sus opiniones) y en realidad sólo hemos conseguido reducir una línea. Pero el problema del último código es que no utiliza todas las posibilidades de Ruby. Veamos otra posibilidad que utiliza algunos detalles muy interesantes de Ruby.
lista = # una lista de palabras, por ejemplo
tabla = Hash.new(0)
lista.each { |palabra| tabla[palabra] += 1 }
Eso sí que es reducir. Pero el que hace la magia aquí yo creo que es el método constructor de la segunda línea. El parámetro que le pasamos al constructor hace que el elemento por defecto que se devuelve cuando se pide el valor de una clave no existente en el hash sea 0 en vez de nil (en el primer ejemplo se utiliza la propiedad de que nil en las comparaciones booleanas se interpreta como falso). Eso permite que la comprobación por si la clave existe y la inicialización a 0 sean innecesarias.
Una gran idea, sin duda, que hace que ese trozo de código que habremos programado 101 veces pierda un if y gane en simplicidad. Para obtener un funcionamiento similar en Java deberíamos programar una subclase de Hashmap ¿Para cuándo un método setDefault(Object value) en la interfaz Map de Java (interfaz que todos los hashes implementan)?
Visto en la página 18 del libro Programming Ruby, The Pragmatic Programmers’ Guide, Second Edition de Dave Thomas con Chad Fowler y Andy Hunt.

