Ir al contenido principal

Sustitución de listas


Definir la función

sustituye :: Eq a => [a] -> [a] -> [a] -> [a]

tal que (sustituye xs ys zs) es la lista obtenida sustituyendo las ocurrencias de la lista no vacía xs en zs por ys. Por ejemplo,

sustituye "as" "_" "las casaderas"   ==  "l_ c_ader_"
sustituye "as" "es" "las casaderas"  ==  "les cesaderes"
sustituye "asa" "a" "las casaderas"  ==  "las caderas"
sustituye "asd" "a" "las casaderas"  ==  "las casaderas"

Soluciones

import Data.List (isPrefixOf, intercalate, stripPrefix)
import Data.List.Split (splitOn)
import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

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

sustituye1 :: Eq a => [a] -> [a] -> [a] -> [a]
sustituye1 _  _ [] = []
sustituye1 xs ys zs@(z:zs')
  | xs `isPrefixOf` zs = ys ++ sustituye1 xs ys (drop (length xs) zs)
  | otherwise          = z : sustituye1 xs ys zs'

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

sustituye2 :: Eq a => [a] -> [a] -> [a] -> [a]
sustituye2 _ _ [] = []
sustituye2 xs ys zs@(z:zs') =
  case stripPrefix xs zs of
    Just resto -> ys ++ sustituye2 xs ys resto
    Nothing    -> z : sustituye2 xs ys zs'


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

sustituye3 :: Eq a => [a] -> [a] -> [a] -> [a]
sustituye3 _ _ [] = []
sustituye3 xs ys zs@(z:zs') =
  maybe (z : sustituye3 xs ys zs')
        (\resto -> ys ++ sustituye3 xs ys resto)
        (stripPrefix xs zs)

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

sustituye4 :: Eq a => [a] -> [a] -> [a] -> [a]
sustituye4 xs ys = intercalate ys . splitOn xs

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

verifica :: IO ()
verifica = hspec spec

specG :: (String -> String -> String -> String) -> Spec
specG sustituye = do
  it "e1" $
    sustituye "as" "_" "las casaderas"  `shouldBe` "l_ c_ader_"
  it "e2" $
    sustituye "as" "es" "las casaderas" `shouldBe` "les cesaderes"
  it "e3" $
    sustituye "asa" "a" "las casaderas" `shouldBe` "las caderas"
  it "e4" $
    sustituye "asd" "a" "las casaderas" `shouldBe` "las casaderas"

spec :: Spec
spec = do
  describe "def. 1" $ specG sustituye1
  describe "def. 2" $ specG sustituye2
  describe "def. 3" $ specG sustituye3
  describe "def. 4" $ specG sustituye4

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

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

-- -- La propiedad es
prop_equivalencia :: NonEmptyList Char -> String -> String -> Bool
prop_equivalencia (NonEmpty xs) ys zs =
  all (== sustituye1 xs ys zs)
      [sustituye2 xs ys zs,
       sustituye3 xs ys zs,
       sustituye4 xs ys zs]

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

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

-- La comparación es
--    λ> :set +s
--    λ> length (sustituye1 "123" "" (take (10^7) (cycle "1234")))
--    2500000
--    (2.39 secs, 1,920,602,240 bytes)
--    λ> length (sustituye2 "123" "" (take (10^7) (cycle "1234")))
--    2500000
--    (2.06 secs, 2,080,602,216 bytes)
--    λ> length (sustituye3 "123" "" (take (10^7) (cycle "1234")))
--    2500000
--    (2.56 secs, 2,340,603,528 bytes)
--    λ> length (sustituye4 "123" "" (take (10^7) (cycle "1234")))
--    2500000
--    (0.56 secs, 2,940,603,136 bytes)