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.