Todos contra todos

¿Cómo se suman los cuadrados de un vector de números en un paradigma tradicional de programación? Se crea un bucle que lo recorre y que guarda las sumas parciales en un acumulador. Sumamente económico en términos de memoria: apenas consume unos pocos bytes en la pila. La versión funcional de la cosa se parece más a sum(x^2), que implica generar un vector de cuadrados y dilapidar memoria.

Así las cosas, en C uno tiende a recorrer y construir resultados parciales. R invita a crear estructuras de datos preprocesados y aplicar sobre ellas funciones resumen. Map y reduce, si se quiere.

Hay operaciones que se avienen perfectamente a este paradigma; otras (por ejemplo, la convolución) no tanto. Crítico es, en cualquier caso, contar con instrumentos que faciliten la construcción de esas estructuras intermedias de datos.

Conocidos son las funciones *pply y otras similares que proporcionan paquetes adicionales. Sin embargo, una de las menos conocidas del programador circunstancial de R es outer.

Esta función tiene características de map y de reduce a un tiempo. Es un map, pero aplica una función de dos argumentos (por ejemplo, el producto) a todas las parejas de entradas de dos vectores (y más en general, dos arrays multidimensionales) produciendo una matriz (un array con dimensión igual a la suma de las de los de entrada).

Un ejemplo de uso (basado en una pregunta en R-help-es) es obtener la suma de las parejas (distintas) de números del vector x <- c(24,12,45,68,45). Una (y mi) solución es:

1
2
3
x <- c(24,12,45,68,45)
tmp <- outer(x, x, "*")
sum(tmp[lower.tri(tmp)])

Otras igual más interesantes están en la ayuda de la función. Y las más, más interesantes de todas van a estar en tu línea de comandos pronto. Seguro.