Memoization: Acelerando funciones recursivas. Ejemplo con Javascript.

En su día hablamos aquí sobre la recursividad y sus “peligros“. Las funciones recursivas son muy costosas a nivel de recursos pues al llamarse a si mismas repiten varias veces el mismo paso ¿hay una solución?

Memoization (memorización) es una técnica consistente en almacenar los resultados de funciones muy costosas para devolverlos directamente en lugar de volver a calcularlos.

Por ejemplo, la siguiente función que ya vimos en un artículo anterior nos permitiría calcular un factorial con javascript:

function factorial(num)
{
    if (num < 0) {
        return 0;
    }
    else if (num == 0) {
        return 1;
    }
    else {
        return (num * factorial(num - 1));
    }
}

¿Podemos optimizar mucho esta función cacheando los datos? Podemos:

function factorial(num) {
    // inicializamos si es necesario
    if (!factorial.cache) {
        factorial.cache = {};
    }
    if (num == 0) {
        return 1;
    } else if (num in factorial.cache) {
    // si ya tenemos en cache el factorial de num, lo devolvemos
        return factorial.cache[num];
    } else {
    factorial.cache[num] = num * factorial(num - 1);
    return factorial.cache[num];
}
 

De esta forma nos ahorramos varias llamadas a la función pues simplemente devolvemos un valor almacenado en memoria. Esta no es una técnica exclusiva de Javascript, podemos utilizarla con otros lenguajes de programación. Javascript sí tiene la particularidad de tratar las funciones como un objeto más, eso nos permite por ejemplo definirle la propiedad cache en el ejemplo de arriba (en otros lenguajes deberíamos pasarle como parámetro a la función el array de valores o declararlo como variable global), esto también nos permite hacer que una función reciba como parámetro una función o devuelva como resultado otra función, lo que se conoce como higher-order function o función de orden superior. Sirviéndonos de esto podríamos declarar una función genérica para nuestro memoization:

const memoization = function(func){
    const cache = {};
    return (...args) => {
        const key = [...args].toString();
        return key in cache ? cache[key] : (cache[key] = func(...args));
    }
}

De esta forma podríamos definir nuestra función factorial() tal que así:

var factorial = memoization(function(num) {		
    return (num <= 1) ? 1 : num * factorial(num-1);
})

Javascript: funciones querySelector() y querySelectorAll()

Las funciones querySelector() y querySelectorAll() existen en Javascript como métodos del objeto document. Ambas nos permiten acceder a elementos del DOM utilizando un selector de CSS.

La función querySelector() nos devolverá el primer elemento que coincida con el selector que le pasemos. Si es un id no habría problema puesto que deberían ser únicos en el documento, pero si se tratase de una clase o un elemento HTML entonces nos devolvería solo la primera ocurrencia:

//Si es un id nos devolverá ese elemento
var i = document.querySelector('#Contenedor');

//pero si es un elemento que existe varias veces
//entonces solo tendremos la primera ocurrencia
var x = document.querySelector('p');

//esto pondría el fondo gris al primer p que haya 
//en nuestro documento
x.style.backgroundColor = "#d9d9d9";

¿Y si queremos todos los elementos?

En ese caso tenemos que usar querySelectorAll(). El funcionamiento es igual que el de querySelector(), pero en este caso nos devolverá un objeto Nodelist que contiene todos los elementos que coincidan con el selector que hemos buscado. En este caso no tendría sentido usarlo con id, ya que debería ser un elemento único.

//Aquí tendríamos una lista estática con todos los elementos p
var x = document.querySelector('p');

¿Y cómo accedemos a los elementos del Nodelist?

Al ser una lista podemos acceder a los elementos contenidos en el Nodelist que nos devuele querySelectorAll() mediante un índice. Podemos conocer el tamaño de la lista accediendo a la propiedad length e iterar todos los elementos dentro de un bucle:

//Aquí tendríamos una lista estática con todos los elementos p
var x = document.querySelector('p');

//ahora los recorremos y, para el ejemplo, cambiaremos el color
//de fondo por un gris
var i;
for (i = 0; i < x.length; i++) {
  x[i].style.backgroundColor = "#d9d9d9";
}

jQuery: Poner el foco en el siguiente elemento usando una clase

Os cuento: un cliente pide que en un formulario que está rellenando, con varios campos de texto muy pequeños para un solo carácter, el foco salte de forma automática al siguiente campo cada vez que cubre uno. Es decir, en cada evento de levantar la tecla salta al siguiente. La cosa parecía simple usando la función next() de jQuery:

$(".cuadrito").keyup(function() {
  $(this).next('.cuadrito').focus();	
});

La función next() de jQuery salta al siguiente elemento “hermano” que aparezca. ¿Qué quiere decir hermano? Pues que tengan el mismo padre, esto es que estén contenidos en el mismo elemento del DOM. Y por eso esta práctica y elegante solución no me valía, porque resulta que los inputs están dentro de una tabla, de forma que al cambiar de celda cambia el “padre” en el DOM y ya no salta el foco. ¿Qué hacer entonces? Lo solucioné con la función index():

$(".cuadrito").keyup(function() {	            
  var ind = $(".cuadrito").index(this);
  $(".cuadrito").eq(ind + 1).focus();
});

¿Qué hicimos aquí? Creo que en el pasado ya vimos que jQuery nos permite tratar a los elementos como si de un array se tratase. Simplemente estoy mirando en la primera fila qué índice tendría el elemento en el que nos encontramos y, en la siguiente, poniendo el foco en el posterior sumando 1 al índice.

Orden de operaciones aritméticas (PEMDAS) y su aplicación en lenguajes de programación.

Todo un clásico en las redes sociales es que alguien comparta la operación 5+4/3-1*2 y que se monte un gallinero tremendo en los comentarios con distintas soluciones. Esto se debe a que mucha gente no tiene claro cómo va la jerarquía de las operaciones y el orden de evaluación de las mismas.

Si hablamos de operaciones básicas, y de la mayoría de lenguajes de programación (Javascript, PHP, Python, Ruby, C,Visual Basic, Java…), nos regiremos por el orden de operaciones conocido por el acrónimo inglés PEMDAS, que en castellano podríamos traducir como PAPOMUDAS (PAréntesis, POtencias, MUltiplicación, División, Adición, Sustracción). En base a esto el orden de operaciones en lenguajes de programación como Python, PHP, Ruby o Javascript sería:

  1. Paréntesis
  2. Potencias y radicales
  3. Multiplicación, división, división entera y módulo.
  4. Suma y resta.

En este enlace puedes comprobar los resultados de distintas operaciones realizados en distintos lenguajes de programación. Puedes copiar los siguientes ejemplos para comprobar que el resultado es el mismo.

Aquí el código en Javascript:

var resultado = 5+4/3-1*2;
console.log(resultado);

Aquí el código en Python:

resultado = 5+4/3-1*2
print(resultado)

Aquí en Java:

public class Test {
  public static void main(String[] args){
    System.out.println(5.0+4.0/3.0-1.0*2.0);
  }
}

Y aquí en C:

void main(void) {
   double resultado;
   resultado = 5.0+4.0/3.0-1.0*2.0;
   printf("%f",resultado);
}

Como puedes comprobar, en todos el resultado es 4.333333 ya que todos usan el mismo orden para las operaciones.

Cálculo del logaritmo y logaritmo neperiano en Javascript.

Ayer me mandaban este chiste por Whatsapp:

Y como soy así de tocahuevos, que hasta llevo un reloj calculadora Casio, les mandé de vuelta el resultado del logaritmo neperiano de 1437. Y sí, estoy escribiendo esto para cuando me lo vuelvan a mandar, para contestar con este enlace, que me vale tanto para la sección de programación como para la de ciencia.

El elcálculo de logaritmos es la operación inversa a la exponenciación de la base del logaritmo. El desarrollo de calculadoras y ordenadores ha hecho que las tablas de logaritmos, que se usaban hace años para simplificar operaciones complejas, hayan perdido mucha importancia para los estudiantes de matemáticas en la actualidad. Este blog nos da una entrada muy intersante sobre el uso de los logaritmos.

La clase Math de Javascript tiene varias funciones para calcular un logaritmo. Para el logaritmo natural (logaritmo cuya base es el número e, un número irracional cuyo valor aproximado es 2,7182818284590452353602874713527):

//vamos a calcular el logaritmo de 5
var logaritmo = Math.log(5);

¿Y para obtener el logaritmo en base 10?

//vamos a calcular el logaritmo de 5
//pero con base decimal
var logaritmo = Math.log10(5);

¿Y para obtener el logaritmo en base 2?

//vamos a calcular el logaritmo de 5
//pero con base binaria
var logaritmo = Math.log2(5);

¿Y el logaritmo neperiano? Bueno, en lenguaje coloquial suele llamarse logaritmo neperiano al logaritmo natural, pero si nos ponemos precisos son dos conceptos disintos. El logaritmo neperiano, nombrado en honor del matemático John Napier, se calcularía con la fórmula -107*ln(x/-107):

//vamos a calcular el logaritmo neperiano
//de 5.
var logaritmo = Math.pow(-10,7)*Mat.log(5/Math.pow(-10,7))

Como puedes ver los logaritmos neperianos son esencialmente logaritmos naturales con la coma desplazada siete posiciones hacia la derecha y el signo invertido.

Calculadora de Ohm en Javascript

La ley de Ohm fue postulada por el físico y matemático Georg Simon Ohm, es una ley básica de los circuitos eléctricos. Nos dice que la diferencia de potencial V que aplicamos entre los extremos de un conductor es proporcional a la intensidad de la corriente I que circula por él. Introduce la noción de resistencia eléctrica R: el factor de proporcionalidad que aparece en la relación entre diferencia potencial e intensidad.

En este ejemplo vamos a hacer una función de Javascript que puede recibir tres parámetros y, según el que reciba vacío, devolverá un resultado u otro valiéndose de la fórmula general de la ley de Ohm, que resumimos en la fórmula V=R*I.

function calculadoraOhm(V,R,I){
  //si la diferencia potencial va vacía
  //en ese caso calculamos el voltaje.
  if(V==""){
    return parseFloat(R)*parseFloat(I);
  }
  //si la resistencia va vacía
  //en ese caso calculamos el voltaje.
  if(R==""){
    return parseFloat(V)/parseFloat(I);
  }
  //si la intensidad va vacía
  //es la que calculamos.
  if(I==""){
    return parseFloat(V)/parseFloat(R);
  }
  //si no va nada vacío devuelve una cadena vacía.
  return "";
}

Cómo hacer un Hello World! en distintos lenguajes de programación.

El Hello World es un ejercicio básico de programación. Casi en cualquier lenguaje de programación que estudies empezarás en la primera lección programando uno. Aquí te dejo diversos ejemplos en distintos lenguajes
, lo que además te permitirá ver algunas de las pequeñas diferencias que hay entre ellos.

ASP:

Response.Write "Hello World!" 

Script de Bash:

#!/bin/bash
echo "Hello, World!" 

C:

#include 
main(){
  printf ("Hello World!\n");
}

C++:

#include 
using namespace std;
void main(){
  cout << "Hello World!" << endl;
}

C#:

using System;
namespace HelloWorld
{
    class Hello 
    {
        static void Main() 
        {
            Console.WriteLine("Hello World!");            
        }
    }
}

Java:

class hellWorldJava{
  public static void main(String args[]){
    System.out.println("Hello World!");
  }
}

Javascript:

window.alert( 'Hello, world!' );

Objective C:

#import 

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
    }
    return 0;
}

Perl:

#!/usr/bin/perl
print “Hello World.\n”;

PHP:

echo "Hello World!";

Script de Powershell:

$strString = "Hello World"
write-host $strString

Python:

print "Hello, World!"

R:

print("Hello World!", quote = FALSE)

Ruby:

puts 'Hello world'