coding challenge

Reto de programación 1: ¿Es un anagrama?

El segundo reto de programación consiste en crear un método que reciba 2 cadenas y devuelva sin son un anagrama o no.

¿Qué es un anagrama?

Un anagrama es una palabra que resulta de la transposición de todas las letras de otra palabra. Dicho de otra forma, una palabra es anagrama de otra si las dos tienen las mismas letras, con el mismo número de apariciones, pero en un orden diferente.

Wikipedia

Es decir, palabras que tienen el mismo número de letras, las mismas letras, pero en diferente orden. Por ejemplo: fresa y frase, panel y nepal, japonés y esponja…

/*
 * Escribe una función que reciba dos palabras (String) y retorne verdadero o falso (Bool) según sean o no anagramas.
 * - Un Anagrama consiste en formar una palabra reordenando TODAS las letras de otra palabra inicial.
 * - NO hace falta comprobar que ambas palabras existan.
 * - Dos palabras exactamente iguales no son anagrama.
 */

Leyendo el enunciado del reto, identificamos claramente varias comprobaciones a realizar:

  • Las dos palabras deben tener el mismo número de letras
  • Las dos palabras deben contener las mismas letras
  • Si las dos palabras son exactamente iguales, no serían un anagrama
  • No hace falta comprobar que las palabras realmente existan, es decir, «palabra» y «plbraaa» sería un anagrama

Voy añadir una casuística más (creo que por sentido común), que sea ignorar mayúsculas, minúsculas y acentos. Este tipo de cosas creo que te darían puntos extra en una prueba técnica. El código quedaría así:

<?php

declare(strict_types=1);

function isAnagram(string $string1, string $string2): bool
{
    $string1 = normalizeString($string1);
    $string2 = normalizeString($string2);

    return ! isSameWord($string1, $string2) && containSameLetters($string1, $string2);
}

function normalizeString(string $str): string
{
    $str = htmlentities($str, ENT_NOQUOTES, 'utf-8');

    $str = preg_replace('#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str);
    $str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str);
    $str = preg_replace('#&[^;]+;#', '', $str);

    return mb_strtolower($str);
}
function isSameWord(string $string1, string $string2): bool
{
    return $string1 === $string2;
}

function containSameLetters(string $string1, string $string2): bool
{
    $arrayOfLetters1 = mb_str_split($string1);
    $arrayOfLetters2 = mb_str_split($string2);

    sort($arrayOfLetters1, SORT_STRING);
    sort($arrayOfLetters2, SORT_STRING);

    return $arrayOfLetters1 === $arrayOfLetters2;
}

En primer lugar lo que hago es normalizar las cadenas de entrada, es decir, elimino acentos y las paso a minúsculas, ya que «A» y «a» no son las mismas letras, ni «a» y «á» por poner un ejemplo. Son códigos ASCII distintos.

Sólo quedarían entonces 2 comprobaciones: que no sea la misma palabra, y que contengan las mismas letras. Para esto lo que hago es descomponer la palabra en un array, y lo ordeno. Si los dos resultan iguales, entonces tenemos un anagrama.

También puedes verlo en GitHub.

¿Te ha resultado útil esta información? 🍺

Si este post te ha resuelto un problema, invítame a un café o a una cerveza. Con este pequeño gesto me animas a seguir escribiendo.

Comentarios

Deja un comentario

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

  • El fin del tratamiento es únicamente la moderación de comentarios para evitar spam
  • La legitimación es tu consentimiento al comentar
  • No se comunicará ningún dato a terceros salvo por obligación legal
  • Tienes derecho al acceso, rectificación y eliminación de los comentarios