Ir al contenido principal

Acrónimos


A partir de una palabra de puede formar un acrónimo uniendo un prefijo de la primera con un sufijo de la segunda. Por ejemplo,

  • "ofimática" es un acrónimo de "oficina" e "informática"
  • "informática" es un acrónimo de "información" y "automática"
  • "teleñeco" es un acrónimo de "televisión" y "muñeco"

Definir la función

esAcronimo :: String -> String -> String -> Bool

tal que (esAcronimo xs ys zs) se verifica si xs es un acrónimo de ys y zs. Por ejemplo,

esAcronimo "ofimatica" "oficina" "informatica"       ==  True
esAcronimo "informatica" "informacion" "automatica"  ==  True

Soluciones

import Data.List (isPrefixOf, isSuffixOf, inits, tails)
import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

esAcronimo1 :: String -> String -> String -> Bool
esAcronimo1 xs ys zs =
  xs `elem` acronimos ys zs

-- (acronimos xs ys) es la lista de acrónimos de xs e ys. Por ejemplo,
--    λ> acronimos "ab" "cde"
--    ["cde","de","e","","acde","ade","ae","a","abcde","abde","abe","ab"]
acronimos :: String -> String -> [String]
acronimos xs ys =
  [us++vs | us <- inits xs, vs <- tails ys]

-- 2ª solución
-- ===========

esAcronimo2 :: String -> String -> String -> Bool
esAcronimo2 xs ys zs =
  or [p `isPrefixOf` ys && s `isSuffixOf` zs |
      (p, s) <- zip (inits xs) (tails xs)]

-- 3ª solución
-- ===========

esAcronimo3 :: String -> String -> String -> Bool
esAcronimo3 xs ys zs =
  or [isPrefixOf us ys && isSuffixOf vs zs |
      (us,vs) <- [splitAt n xs | n <- [0..length xs]]]

-- 4ª solución
-- ===========

esAcronimo4 :: String -> String -> String -> Bool
esAcronimo4 xs ys zs = any cumpleCondicion particiones
  where
    particiones = [splitAt k xs | k <- [0 .. length xs]]
    cumpleCondicion (p, s) = p `isPrefixOf` ys && s `isSuffixOf` zs

-- 5ª solución
-- ===========

esAcronimo5 :: String -> String -> String -> Bool
esAcronimo5 xs ys zs =
  longPrefijo xs ys + longSufijo xs zs >= length xs

-- (longPrefijo xs ys) es el máximo número de caracteres que coinciden
-- al principio de xs e ys. Por ejemplo,
--    longPrefijo "ofimatica" "oficina" == 3
longPrefijo :: String -> String -> Int
longPrefijo xs ys =
  length (takeWhile id (zipWith (==) xs ys))

-- (longSufijo xs ys) es el máximo número de caracteres que coinciden
-- al final de xs e ys. Por ejemplo,
--    longSufijo "ofimatica" "automatica" == 6
longSufijo :: String -> String -> Int
longSufijo xs ys =
  longPrefijo (reverse xs) (reverse ys)

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: (String -> String -> String -> Bool) -> Spec
specG esAcronimo = do
  it "e1" $
    esAcronimo "ofimatica" "oficina" "informatica"       `shouldBe`  True
  it "e2" $
    esAcronimo "informatica" "informacion" "automatica"  `shouldBe`  True

spec :: Spec
spec = do
  describe "def. 1" $ specG esAcronimo1
  describe "def. 2" $ specG esAcronimo2
  describe "def. 3" $ specG esAcronimo3
  describe "def. 4" $ specG esAcronimo4
  describe "def. 5" $ specG esAcronimo5

-- La verificación es
--    λ> verifica
--    10 examples, 0 failures

-- Comprobación de equivalencia
-- ============================

-- Definimos un tipo de dato para nuestros casos de prueba
data Ejemplo = E String String String
  deriving Show

-- Generador de ejemplos formados por tres cadenas aleatorias. Por ejemplo,
--    λ> generate ejemploAleatorio
--    E "xzkyfgdmnkifjxswflcucsoki" "ij" "hudbauuymqbixlygyqrsbyclbup"
ejemploAleatorio :: Gen Ejemplo
ejemploAleatorio = do
  xs <- listOf (elements ['a'..'z'])
  ys <- listOf (elements ['a'..'z'])
  zs <- listOf (elements ['a'..'z'])
  return (E xs ys zs)

-- Generador de ejemplos formados por tres cadenas tales que la primera
-- es acrónimo de la segunda y la tercera.. Por ejemplo,
--    λ> generate ejemploValido
--    E "dqvjbbfdmglqvjrpwcze" "dqvjbbfdmggu" "sxjxlqvjrpwcze"
ejemploValido :: Gen Ejemplo
ejemploValido = do
  ys <- listOf (elements ['a'..'z'])
  zs <- listOf (elements ['a'..'z'])
  lenP <- choose (0, length ys)
  let p = take lenP ys
  lenS <- choose (0, length zs)
  let s = drop (length zs - lenS) zs
  let xs = p ++ s
  return (E xs ys zs)

-- Ejemplo es una subclase de Arbitrary.
instance Arbitrary Ejemplo where
  arbitrary = frequency
    [ (1, ejemploAleatorio), -- 10% de veces: cadenas totalmente aleatorias
      (9, ejemploValido)     -- 90% de veces: acrónimos construidos válidos
    ]

-- La propiedad es
prop_esAcronimo :: Ejemplo -> Bool
prop_esAcronimo (E xs ys zs) =
  all (== esAcronimo1 xs ys zs)
      [esAcronimo2 xs ys zs,
       esAcronimo3 xs ys zs,
       esAcronimo4 xs ys zs,
       esAcronimo5 xs ys zs]

-- La comprobación es
--    λ> quickCheck prop_esAcronimo
--    +++ OK, passed 100 tests.

-- La propiedad para que indique el porcentaje de ejemplos válidos
-- generados.
prop_esAcronimo2 :: Ejemplo -> Property
prop_esAcronimo2 (E xs ys zs) =
  collect resultado1 $ all (== resultado1)
                           [esAcronimo2 xs ys zs,
                            esAcronimo3 xs ys zs,
                            esAcronimo4 xs ys zs,
                            esAcronimo5 xs ys zs]
  where resultado1 = esAcronimo1 xs ys zs

-- La comprobación es
--    λ> quickCheck prop_esAcronimo2
--    +++ OK, passed 100 tests:
--    88% True
--    12% False
--    (0.06 secs, 39,303,544 bytes)

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> ej1 = replicate 500 'a'
--    λ> ej2 = replicate 500 'b'
--    λ> ej3 = ej1 ++ ej2
--    λ> esAcronimo1 ej3 ej1 ej2
--    True
--    (1.14 secs, 3,547,840,920 bytes)
--    λ> esAcronimo2 ej3 ej1 ej2
--    True
--    (0.01 secs, 5,918,168 bytes)
--    λ> esAcronimo3 ej3 ej1 ej2
--    True
--    (0.01 secs, 16,846,824 bytes)
--    λ> esAcronimo4 ej3 ej1 ej2
--    True
--    (0.03 secs, 16,810,696 bytes)
--    λ> esAcronimo5 ej3 ej1 ej2
--    True
--    (0.01 secs, 794,488 bytes)
--
--    λ> ej4 = replicate 20000 'a'
--    λ> ej5 = replicate 20000 'b'
--    λ> ej6 = ej4 ++ ej5
--    λ> esAcronimo2 ej6 ej4 ej5
--    True
--    (3.64 secs, 9,576,349,584 bytes)
--    λ> esAcronimo3 ej6 ej4 ej5
--    True
--    (11.29 secs, 25,610,518,784 bytes)
--    λ> esAcronimo4 ej6 ej4 ej5
--    True
--    (11.31 secs, 25,609,078,680 bytes)
--    λ> esAcronimo5 ej6 ej4 ej5
--    True
--    (0.01 secs, 8,438,528 bytes)