Desafios en JavaScript, ronda 1 | Soluciones

A modo de resumen, expongo en esta entrada algunas de las soluciones a los problemas expustos en la entrada anterior. En este tema del foro Foros del Web, se pueden ver distintas soluciones volcadas por los usuarios de dicha comunidad.

Problema 1

Crear una función que genere un output en la consola de los 100 primeros números sin utilizar ni bucles* ni condicionales**.

Para ver la recopilación de soluciones, pueden dirigirse a la entrada ¿Podrías hacerlo sin if? de @joseanpg.

De las soluciones que no utilizan iteración implícita o condicionales ocultos (try/catch por ejemplo), en la mayoría se nota la intención de utilizar un diccionario con dos entradas, una para el comportamiento del loop hasta el 100 (display del número y recursión) y otra que simplemente no hace nada.
Las variantes que se ven en este tipo de soluciones implican modificar el tipo de dato del diccionario (array u object) así como también el método de selección de entrada.

Mi segunda solución es uno de estos casos, donde se utiliza un array con dos funciones y un operador binario para decidir la entrada a ejecutar:

// La funcion recibe tres
// argumentos, el inicio y fin de la iteracion
// y un handler, que en este caso sera el metodo
// console.log
(function(from, to, handler) {

	// Funcion interna
	(function cycle(n) {
		// Nuestro diccionario
		[
			// La primer entrada termina
			// la recursion
			function() {},
			// La segunda muestra el resultado
			// y recursa la función para el siguiente
			// numero
			function(n) {
				handler(n);
				cycle(n+1)
			}
			// Aqui esta la logica, 1^(n/to) evaluara
			// a 0 cuando el orden de la iteracion sea
			// igual al limite requerido (en este caso 100)
		][1^(n/to)](n) // Pasamos como argumento el numero actual
	})(from);

})(0, 100, console.log);

Otra lógica (bastante particular por cierto), es la del usuario @panino5001, en la cual utiliza un intervalo con un corte de control basado en clearTimeout (solución ligeramente modificada):

(function (from, to, handler) {
	var o = [];

	// La funcion que se ejecutara
	function f() {
		handler(++from);
		// Terminamos el intervalo en la
		// "vuelta" actual. Esto se cumple
		// unicamente en la vuelta final
		clearInterval(o[from]);
	}

	// Comenzamos a ejecutar el intervalo
	// registrando su id en la "vuelta" final
	o[to] = setInterval(f, 0);
 })(0, 100, console.log);

Problema 2

Crear una función f tal que:

f('This ')('i')('s a sentence')() + f('123')() == 'This is a sentence123'

Este problema no representa demasiada dificultad, y su solución en su forma más sencilla es la siguiente:

function f(s) {
	// Devolvemos una funcion que tiene visibilidad sobre el
	// argumento s (forma un clousure)
	return function sub(a) {
		// Concatenamos el argumento si existiese
		s += a || '';
		// Si existe el argumento devolvemos la funcion actual
		// caso contrario el string resultado
		return a ? sub : s;
	}
}

Mi solución fue ligeramente más elaborada (saliendo de la consigna), permitiendo que cada llamada a la función pueda recibir multiples strings.

Problema 3

Crear una función getMax(a, b), que recibe dos números como argumentos y debe devolver (obviamente) el mayor de ellos. No se pueden utilizar los operadores < , >, ==, != ni funciones nativas con funcionalidad similar (Math.max, Math.min).
Como segundo nivel, se resuelve el mismo problema sin utilizar condicionales ni bucles (aclaraciones similares al problema 1).

Este sea probablemente el problema que abarca más tipos de soluciones, por lo cual vamos a centrarnos en las más originales y menos rebuscadas:

Utilizando condicionales, por Neil Fraser:

function getMax(a, b) {
	var diff = a - b;
	// La primer expresion evalua en 0
	// en el caso b > a
	return (diff - Math.abs(diff)) ? b : a;
}

Sin condicionales, se puede utilizar un Array.sort (bucle implícito) con la lógica deseada y obtener el registro correspondiente. Otra forma es implementando un diccionario nuevamente, en este caso la solución es de autoría de Michael Geary.

function getMax(a, b) {
	return arguments[ Number(!/-/.test( b - a ))];
}

// Version no remix
function getMax(a, b) {
	var diff,
		index;

	// Calculamos la diferencia
	diff = b - a;

	// Casteamos a string el resultado
	diff = String(diff);

	// Verificamos si el string contiene el simbolo -
	// Convertimos a Number el resultado booleano
	// siendo tal que true -> 1 y false -> 0
	return arguments[Number(!/-/.test(diff))];
}

Finalmente, tenemos una solución basada enteramente en operadores binarios, por parte de @panino5001:

function getMax(x, y){
    return  x ^ ((x ^ y) & -((~(y -x ) >> 31) & 1));
}

La unica desventaja de este método es que falla para números grandes (a partir de 2 ^ 16 para este caso particular).



4 views shared on this article. Join in...

  1. Andrés Fernández dice:

    Excelente!
    Muy buena la iniciativa en Foros del Web, y muy buenos el seguimiento y el cierre.
    Felicitaciones también por tu blog!

  2. Dmitry Pashkevich dice:

    Hola! Gracias por tu blog, muy interesante. Quiero compartir mi solucion para Problema 2, un poquito mas corta que la presentada:

    function f(s) {
    	return function(k) {
    		return k ? f(s+k) : s;
    	}
    }
    

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Comment

You may use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>