codewars

Ejercicio resuelto: semáforo con JavaScript

En este post veremos la solución a un ejercicio sencillo de JavaScript. Se trata de crear una función que regrese “amarillo”, “rojo”, o “verde” dependiendo del argumento que reciba indicando la luz encendida actualmente.

La función va a indicar cuál es la luz que debería encender de acuerdo a la que está encendida actualmente.

Si la luz es “rojo” entonces debe mostrar “verde”, si es “verde” debe mostrar “amarillo” y finalmente si es “amarillo” debe mostrar “rojo”.

Por cierto, este es un ejercicio de Codewars.

Continue reading…

Algoritmo en JavaScript: elevador más cercano

Resolviendo otro ejercicio de CodeWars me encontré uno en donde nos pide que hagamos una función que indique el elevador (izquierda o derecha) más cercano a un piso de un edificio. Dice más o menos así:

Existen 2 elevadores en un edificio, uno que está a la izquierda y otro a la derecha en un edificio que tiene 3 pisos (numerados del 0 al 2). Escribe una función que reciba el número de piso del elevador de la izquierda, el de la derecha y el piso en el que es llamado. Dicha función debe regresar el nombre del elevador que esté más cercano al piso en el que se llama. Si ambos están a la misma distancia entonces que regrese el de la derecha.

En resumen debería regresar “izquierda” o “derecha” dependiendo del elevador que esté más cercano al piso en donde se llama. Si la distancia es la misma, que regrese “derecha”.

Continue reading…

Pangrama en Python

Hoy veremos cómo saber si una cadena u oración es un pangrama en Python.

Un pangrama es un texto que usa todas las letras posibles del alfabeto de un idioma.

Voy a explicar dos maneras de saber si una cadena es un pangrama usando Python; la primera forma recorre el alfabeto y comprueba si cada letra está dentro de la cadena, en caso de que todas las letras estén dentro de la cadena, se dice que sí es pangrama.

El segundo método utiliza conjuntos (tutorial aquí), comparando si todos los elementos del alfabeto están dentro del conjunto de la cadena.

Nota: este es un ejercicio de Codewars.

Continue reading…

JavaScript: comprobar si números están ordenados en orden ascendente

Introducción

Hoy veremos otro ejercicio de codewars muy simple. Se trata de comprobar si todos los números en un arreglo están en orden ascendente.

Recordemos que un arreglo, vector o array es una colección de elementos. Uno de números, ordenado de manera ascendente se vería así:

[1, 4, 5, 80, 100, 500]

En cambio, uno no ordenado de manera ascendente, así:

[1, 3, 2, 50, 80]

Nuestra tarea es escribir una función que compruebe si los elementos están o no ordenados de esa manera.

Solución

La solución que yo propuse es la siguiente:

Si JavaScript ya provee una forma de ordenar arreglos con array.sort, entonces ordenamos el arreglo  (de manera ascendente) y lo guardamos en una variable.

Luego, comparamos el arreglo original con el que ya ordenamos previamente y si son exactamente iguales, entonces la respuesta es que el arreglo original sí estaba ordenado de esa forma.

El código es este:

const inAscOrder = arr => arr.join("") === arr.sort((a, b) => a-b).join("");

Muy corto pero lo que hacemos es ver si al convertir ambos arreglos a cadena son iguales. Esto, en código más expresivo y compatible con versiones anteriores de JS, se vería así:

var inAscOrder = function inAscOrder(arr) {
  return (
    arr.join("") ===
    arr
      .sort(function(a, b) {
        return a - b;
      })
      .join("")
  );
};

Probando

Aquí una prueba llamando a la función:

Otra solución

La solución que obtuvo más votos es esta:

function inAscOrder(arr) {
  return arr.every(function(_, i) {
    return i == 0 || arr[i] > arr[i - 1];
  });
}

Llamamos a la función every de los arreglos. Esta función devuelve true si, al iterar todo el arreglo, se devuelve true dentro de la función.

Con una vez que la condición no se cumpla (es decir, aunque 100  veces sea true pero 1 sea false) entonces se devuelve false.

Para devolver true o false, dentro de la función comparamos  si el valor actual es mayor que el valor anterior.

En la primera iteración no podremos comparar con el valor anterior (porque accederíamos al índice -1) pero por ello está la condición que dice:

Devuelve true si i (o sea, el índice) es 0, o el elemento actual es mayor al anterior.

Error en la solución

No sé si haya un error en esta solución, ya que al probarla con un arreglo así:

[1, 4, 5, 80, 80, 100, 500]

Devuelve false.

Pero si miramos al arreglo, todos los datos están en orden ascendente. El 80 se repite, pero no por ello cambia el orden. Lo que pasa es que se está comparando si es mayor, no mayor o igual.

Para arreglar esto, el código quedaría así:

function inAscOrder(arr) {
  return arr.every(function(_, i) {
    return i == 0 || arr[i] >= arr[i - 1];
  });
}

Con estos resultados:

Python y Codewars: baches en el camino

Introducción

Hay un ejercicio que aunque no es tan difícil sí que es entretenido. Se trata de contar los baches en un camino y diagnosticar si nuestro auto (suponiendo que tenemos uno) podrá llegar sano y salvo a casa.

El problema dice algo así:

Suponiendo que tenemos un auto y el amortiguador de éste sólo soporta pasar sobre 15 baches antes de romperse, escribir una función que reciba el camino como una cadena (ya veremos más adelante cómo es) y devuelva “Woohoo!” si llegaremos sanos a casa o “Car Dead” en caso contrario.

El camino es representado por _ o n, es decir, guiones bajos y letras ene. Si es un guión bajo entonces el camino está “plano” pero si encontramos una n significa que hay un bache.

Un ejemplo del camino podría ser: __n__ en donde hay 1 bache. En cambio, este: ___nn_nnn_n_n tiene 7 baches y este: _________ no tiene baches.

Solución

Muy fácil, contamos cuántas veces aparece n dentro de la cadena que recibimos. Si el conteo es menor o igual a 15, regresamos “Woohoo!” y en caso de que no, “Car Dead”. Así:

def bumps(road):
    return "Woohoo!" if road.count("n") <= 15 else "Car Dead"

Está un poco resumido, pero podría expandirse así:

def bumps(road):
    conteo = road.count("n")
    if conteo <= 15:
        return "Woohoo!"
    else:
        return "Car Dead"

Y para probar podemos hacer esto:

print(bumps("___n_n_n______________n"))# Woohoo!, pues sólo hay 4
print(bumps("n__nnnn__nn___nnnnnnnnnn________"))# Car Dead, porque hay 17
print(bumps("____nnnn___________nnnnn_______n_n_n_n_"))# Wohoo! porque hay 13

Con estos resultados:

Fue un ejercicio que me gustó mucho.

Python: función que regresa el número 5 sin usar números ni operadores

Introducción

Continuando con algunos ejercicios de codewars, esta mañana me topé con uno muy interesante que me hizo pensar más de lo que debería.

Se trataba de algo muy, muy simple: escribir una función que regresara el número 5 utilizando el lenguaje Python. Algo así:

def regresar_cinco():
  return 5

Pero con algunas restricciones: no usar números, ni operadores aritméticos. Es decir, estaba prohibido usar 0123456789 y /*-+

Así que no podías hacer algo como regresar 4 + 1 o cosas de esas.

Solución

Después de pensar por algunos minutos, me di cuenta de que se podía regresar la longitud de una cadena definida por nosotros mismos.

La palabra “hello” así como “asdfg”, “luiss” y otras tienen una longitud de 5, por lo que nada costaba hacer esto:

def regresar_cinco():
  return len("hello")

Y no iba contra las reglas, pues no usamos ningún operador ni número. He aquí el programa ejecutándose en una sesión REPL:

Python: función que regresa número, pero sin escribir números u operadores

Python: función que regresa número, pero sin escribir números u operadores

Con eso terminamos por hoy.

The Feast of Many Beasts (La fiesta de muchas bestias) solución Javascript

Introducción

Resolviendo ejercicios de codewars, encontré uno que no es nada difícil pero me gustó mucho. Se trata de la fiesta de muchas bestias. Es muy simple.

¡Todos los animales están teniendo una fiesta! Cada animal trae un plato. Sólo hay una regla: el plato debe comenzar y terminar con las mismas letras que el nombre del animal.

Escribe una función “fiesta” que tome el nombre y el plato del animal como argumentos y devuelva verdadero o falso para indicar si la bestia puede llevar el plato a la fiesta.

Puedes suponer que la bestia y el plato siempre son cadenas minúsculas, y que cada una tiene al menos dos letras. Bestia y plato pueden contener guiones y espacios, pero estos no aparecerán al principio o al final de la cadena, tampoco contendrán números.

Solución

Lo único que tenemos que haces es obtener el primer y último carácter del nombre de la bestia y el nombre del plato, para más tarde compararlos.

Obtenemos la primera letra del nombre del animal, y la comparamos con la primera letra del plato. Después, obtenemos la última letra del nombre del animal, y la comparamos con la última letra del plato.

Devolvemos lo que salga al comprobar si las dos condiciones se cumplen. Es decir, si ambas se cumplen se devolverá true. Y si no, false.

Código

He aquí el código.

Con una versión anterior de Javascript queda así:

Finalmente, para que se entienda mejor, podríamos ponerlo así:

Python: Volumen y área total de una caja

Introducción

Esto es otro ejercicio sacado de codewars. Se trata de calcular el volumen y el área total de una caja, y devolverlos en una lista. El problema dice más o menos así:

Dada la altura, anchura y profundidad de una caja, calcular su volumen y su superficie o área total.

Es decir, tenemos que devolver el volumen, y la suma de la superficie de cada cara. Recordemos que es una caja, no un cubo.

Imagen explicativa

Al principio me confundí y pensé que era un cubo, pero es una caja. Una caja como las que tenemos en casa, esas en donde guardamos cosas. Es así:

Créditos al respectivo autor de la imagen, aunque cuando me la robé, puse “Etiquetadas para reutilización” en la búsqueda, pero no hay que confiarse.

Nota: Width es profundidad, Length anchura y Height altura. Tal vez no lo sea así para los matemáticos, pero para este ejercicio sí.

Calcular volumen y área total

Ahora sí vamos a la función.

Calcular volumen

Para esto, simplemente multiplicamos anchura por altura por profundidad. No importa el orden ni las medidas, porque siempre dará el mismo resultado.

Calcular área

Para esto, sólo se me ocurrió multiplicar primero la anchura por la profundidad, y con eso obtenía la superficie de la cara de arriba. Eso lo multiplicaba por 2, pues la cara de abajo y arriba miden lo mismo.

Luego, al resultado anterior le sumé el resultado de multiplicar la altura por la profundidad; con eso obtenía la superficie de una cara lateral. Y a eso lo multiplicaba por 2, pues del otro lado la cara era igual.

Y finalmente, sumaba a los resultados anteriores el resultado de multiplicar la anchura por la altura por 2. Ya que con anchura y altura obtenemos la superficie de la cara de adelante.

Solución al ejercicio

Una vez explicado eso, el ejercicio queda así:

Y pasa correctamente las pruebas:

PostgreSQL: Separar una cadena con expresión regular y poner los resultados en filas

Introducción

Este es otro ejercicio de codewars que estuve a punto de resolver correctamente, aunque al final utilicé unos métodos no recomendados para el ejercicio, pero funcionaron.

El problema era el siguiente:

Dada una cadena aleatoria, partirla en diferentes filas cada que se encontrara cualquier vocal. Por ejemplo, veamos esta cadena:

ah7ki3eumgpa72mdpwe8od

Si la partimos o hacemos un split en cada vocal, sin incluir las vocales, tendríamos un resultado así:

h7k
3
mgp
72mdpw
8
d

Pues exactamente eso se tenía que hacer usando una consulta.

Paso 1: Separar usando expresión regular

En el mismo ejercicio nos aconsejan, aunque no es obligatorio, usar expresiones regulares. En PostgreSQL existe una función que, con un valor y una expresión regular devuelve un arreglo en donde cada valor corresponde a la porción separada: REGEX_SPLIT_TO_ARRAY

La forma de usarla fue la siguiente:

SELECT REGEXP_SPLIT_TO_ARRAY(cadena_aleatoria) AS resultados FROM tabla;

Y devolvía algo así (un arreglo):

{h7k,3,mgp,72mdpw,8,d}

Pero esas no eran filas, eran una sola fila con un arreglo. Entonces busqué la forma de convertir ese arreglo en filas.

Por cierto, la expresión regular es [aeiou], lo que significa que coincidirá cada que encuentre cualquier valor de los que están en el conjunto.

Paso 2: convertir arreglo en filas

Para ello utilicé la función UNNEST, que expande los elementos de un arreglo a filas. Por lo que si el arreglo era {h7k,3,mgp,72mdpw,8,d}, al llamar a esta función se convertía en:

h7k
3
mgp
72mdpw
8
d

La consulta quedó así al final:

SELECT UNNEST(REGEXP_SPLIT_TO_ARRAY(cadena_aleatoria, '[aeiou]')) 
AS resultados 
FROM tabla;

Solución con buenas prácticas

Después de haber mandado esa solución que ya he expuesto, vi la que implementaba las mejores prácticas. Y era casi una combinación de ambas funciones: REGEXP_SPLIT_TO_TABLE

Como su nombre lo dice, separa en filas de acuerdo a una expresión regular.

Conclusión

Siempre se aprenden cosas nuevas, y qué mejor que en codewars, en donde miles de expertos y no tan expertos califican y comparten las soluciones de las pruebas.

Por cierto, el ejercicio o kata es este.

Remover primer y último carácter en Python

Comenzaré a publicar algunas soluciones a algunos sencillos katas de codewars.com. En este caso, el objetivo es, dada una cadena, devolverla pero sin el primer y último carácter. La solución (claro que hay otras y mejores) es la siguiente:

def remove_char(s):
    return s[ 1:len(s) - 1]

Simplemente estamos cortando la cadena desde el 1 hasta n-1, en donde n es la longitud de la cadena. Le restamos uno a dicha longitud porque recordemos que los índices comienzan en 0, por lo que si nuestra cadena es hola, su longitud es 4 pero la última letra tiene el índice 3.

La mejor solución por votos, es esta:

def remove_char(s):
    return s[1 : -1]