Entradas en "pieze of code"

IDs 煤nicas

Volvemos con los problemas de la semana. Este es uno de mis favoritos, muy 煤til para usar en una entrevista de trabajo si quer茅is poner a prueba al candidato 馃槈 (deber铆a hacer una colecci贸n con este tipo de problemas, porque son simples, pero demuestran mucho de quien los resuelve; me gustan mucho!).

Pregunta: En cualquier lenguaje de programaci贸n, escribe una funci贸n UID que devuelva un ID (n煤mero) 煤nico cada vez que se ejecute.

Consideraciones: La funci贸n no puede hacer uso de datos o variables globales de ninguna forma ni aceptar par谩metros. Toda su funcionalidad debe quedar encapsulada. Tampoco puede ser el m茅todo de un objeto.

Ejemplo de ejecuci贸n:

x=UID(); //x vale 1
x=UID(); //x vale 2
x=UID(); //x vale 3
/* Nota: Los n煤meros pueden o no ser secuenciales,
 el 煤nico requisito es que nunca se repitan. */

Expansi贸n (para los que quieran sumar puntos extra): Escribe en cualquier lenguaje de programaci贸n, una funci贸n GUID que devuelva una funci贸n (o puntero a funci贸n en lenguajes como C++) seg煤n las especificaciones del problema anterior pero que funcionen de forma independiente.

Ejemplo de ejecuci贸n:

UID1=GUID();
UID2=GUID();
UID3=GUID();
x=UID1(); //x vale 1
x=UID1(); //x vale 2
x=UID2(); //x vale 1
x=UID1(); //x vale 3
x=UID2(); //x vale 2
x=UID1(); //x vale 4
x=UID3(); //x vale 1

*** SOLUCI脫N ***

El enunciado era sencillo pero la soluci贸n puede complicarse si no tomamos una primera decisi贸n correcta. Erful consigui贸 resolverlo en Javascript (aunque no ten铆a Internet y no pudo responder con su c贸digo) y StormByte iba muy bien encaminado con la soluci贸n.

La primera decisi贸n correcta e importante es la elecci贸n lenguaje de programaci贸n; en algunos lenguajes la soluci贸n es trivial… por eso es importante, cuando leemos “en cualquier lenguaje de programaci贸n”, no interpretarlo como “nuestro favorito” o “el que m谩s dominamos”; si no “el m谩s adecuado” para el problema.

Necesitamos un lenguaje que soporte clausuras o c谩lculo lambda.

Con esto, vamos con las soluciones:

Soluci贸n Simple en Javascript:

var UID = (function() {
   var id=0; return function() {
      return ++id;
   }
})();
//===========================
var x;
x=UID(); //x vale 1
x=UID(); //x vale 2
x=UID(); //x vale 3

Lo que tenemos es la creaci贸n de una funci贸n an贸nima que se ejecuta conforme es definida. Esta funci贸n forma la clausura que contiene a una variable id inicializada a 0. Adem谩s la funci贸n devuelve otra funci贸n que retorna e incrementa el valor de id, esta funci贸n es la que se asigna a UID, y que cada vez que se ejecuta, tiene acceso a la variable id de 谩mbito superior que pertenece a la clausura de la funci贸n an贸nima.

Con esta idea, hacer un generador de funciones UID es trivial:

Soluci贸n Expandida en Javascript:

function GUID() {
   var id=0;
   return function() {
      return ++id;
   }
};
//===========================
var UID1=GUID();
var UID2=GUID();
x=UID1(); //x vale 1
x=UID1(); //x vale 2
x=UID2(); //x vale 1
x=UID1(); //x vale 3
x=UID2(); //x vale 2

La diferencia es que la funci贸n an贸nima de clausura original, ya no es an贸nima, si no que se llama GUID y se ejecuta creando una nueva clausura cada vez, devolviendo la funci贸n que incrementa y devuelve el valor de id.

En otros lenguajes de programaci贸n el planteamiento es el mismo:

Soluci贸n Expandida PHP

function GUID() {
   $id=0;
   return function() use (&$id) {
      return ++$id;
   };
}
//===========================
$UID1=GUID();
$UID2=GUID();
echo $UID1(); //1
echo $UID1(); //2
echo $UID2(); //1
echo $UID1(); //3
echo $UID2(); //2

Fijaos en la sintaxis, para ejecutar UID1 y UID2 no se utiliza la sintaxis de llamada a funci贸n normal; si no que es necesario indicar que son variables: as铆 a() != $a(). Requiere PHP >= 5.3 para funcionar.

Soluci贸n Expandida C++

#include <iostream>
#include <functional>

//===========================
std::function<int()> GUID()
{
    return []()->std::function<int()>
    {
        int id=0;
        return [=]() mutable -> int { return ++id; };
    }();
}
//===========================

int main(int argc, char * argv[])
{
    auto UID1= GUID();
    auto UID2= GUID();

    std::cout << UID1() << std::endl; //1
    std::cout << UID1() << std::endl; //2
    std::cout << UID2() << std::endl; //1
    std::cout << UID1() << std::endl; //3
    std::cout << UID2() << std::endl; //2
    return 0;
}

Para simplificar y evitar el uso de punteros a funciones usamos el tipo function de c++11 (la 煤ltima versi贸n del est谩ndar C++, requiere G++>=4.7). Usamos el c谩lculo lambda para crear la clausura necesaria y devolver la funci贸n. Si quer茅is aprender sobre la sintaxis del c谩lculo lambda en C++ est谩 bien explicada en la documentaci贸n de referencia de MSDN.

驴Os anim谩is a hacer la prueba en otros lenguajes? 馃槈 驴Qui茅n nos ense帽a una soluci贸n en LISP o SCHEME?

Leer m谩s