Ir al contenido principal

Elementos no repetidos


Definir la función

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

tal que (noRepetidos xs) es la lista de los elementos no repetidos de la lista xs. Por ejemplo,

noRepetidos [3,2,5,2,4,7,3]  ==  [5,4,7]
noRepetidos "noRepetidos"  ==  "nRptids"
noRepetidos "Roma"  ==  "Roma"

Soluciones

import Data.Map as M (Map, empty, findWithDefault, fromListWith, insertWith, lookup)
import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

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

noRepetidos1 :: Eq a => [a] -> [a]
noRepetidos1 xs =
 [x | x <- xs, ocurrencias x xs == 1]

-- (ocurrencias x ys) es el número de ocurrencias de x en ys. Por
-- ejemplo,
--    ocurrencias 3 [3,2,5,2,4,7,3]  ==  2
--    ocurrencias 5 [3,2,5,2,4,7,3]  ==  1
ocurrencias :: Eq a => a -> [a] -> Int
ocurrencias x ys =
 length [y | y <- ys, y == x]

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

noRepetidos2 :: Eq a => [a] -> [a]
noRepetidos2 [] = []
noRepetidos2 (x:xs) | elem x xs = noRepetidos2 [y | y <- xs, y /= x]
                    | otherwise = x : noRepetidos2 xs

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

noRepetidos3 :: Ord a => [a] -> [a]
noRepetidos3 xs =
  [x | x <- xs, M.lookup x d == Just 1]
  where d = dicOcurrencias xs

-- (dicOcurrencias xs) es el diccionario formado por los elementos de xs
-- junto con el número de sus ocurrencias en xs. Por ejemplo,
--    λ> dicOcurrencias [3,2,5,2,4,7,3]
--    fromList [(2,2),(3,2),(4,1),(5,1),(7,1)]
dicOcurrencias :: Ord a => [a] -> Map a Int
dicOcurrencias xs = fromListWith (+) [(x, 1) | x <- xs]

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

noRepetidos4 :: Ord a => [a] -> [a]
noRepetidos4 xs =
  [x | x <- xs, findWithDefault 1 x d == 1]
  where d = dicOcurrencias2 xs

dicOcurrencias2 :: Ord a => [a] -> Map a Int
dicOcurrencias2 =
  foldr (\x d -> insertWith (+) x 1 d) empty

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

noRepetidos5 :: Ord a => [a] -> [a]
noRepetidos5 xs = aux xs
  where
    d = dicOcurrencias2 xs
    aux [] = []
    aux (y:ys)
      | findWithDefault 0 y d == 1 = y : aux ys
      | otherwise                  = aux ys

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

verifica :: IO ()
verifica = hspec spec

specG :: ([Int] -> [Int]) -> Spec
specG noRepetidos = do
  it "e1" $
    noRepetidos [3,2,5,2,4,7,3] `shouldBe` [5,4,7]

spec :: Spec
spec = do
  describe "def. 1" $ specG noRepetidos1
  describe "def. 2" $ specG noRepetidos2
  describe "def. 3" $ specG noRepetidos3
  describe "def. 4" $ specG noRepetidos4
  describe "def. 5" $ specG noRepetidos5

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

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

-- La propiedad de equivalencia es
prop_noRepetidos :: [Int] -> Bool
prop_noRepetidos xs =
  all (== noRepetidos1 xs)
      [noRepetidos2 xs,
       noRepetidos3 xs,
       noRepetidos4 xs,
       noRepetidos5 xs]

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

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

-- La comparación es
--    λ> length (noRepetidos1 ([1..1000] ++ [500..4000]))
--    3499
--    (2.85 secs, 1,137,498,936 bytes)
--    λ> length (noRepetidos2 ([1..1000] ++ [500..4000]))
--    3499
--    (0.38 secs, 327,159,984 bytes)
--    λ> length (noRepetidos3 ([1..1000] ++ [500..4000]))
--    3499
--    (0.04 secs, 6,064,784 bytes)
--    λ> length (noRepetidos4 ([1..1000] ++ [500..4000]))
--    3499
--    (0.03 secs, 5,988,992 bytes)
--    λ> length (noRepetidos5 ([1..1000] ++ [500..4000]))
--    3499
--    (0.03 secs, 6,233,016 bytes)
--
--    λ> length (noRepetidos2 ([1..1000] ++ [500..20000]))
--    19499
--    (3.09 secs, 1,882,444,712 bytes)
--    λ> length (noRepetidos3 ([1..1000] ++ [500..20000]))
--    19499
--    (0.07 secs, 29,240,808 bytes)
--    λ> length (noRepetidos4 ([1..1000] ++ [500..20000]))
--    19499
--    (0.03 secs, 31,419,192 bytes)
--    λ> length (noRepetidos5 ([1..1000] ++ [500..20000]))
--    19499
--    (0.07 secs, 32,559,216 bytes)
--
--    λ> length (noRepetidos3 ([1..1000] ++ [500..600000]))
--    599499
--    (1.10 secs, 1,057,491,808 bytes)
--    λ> length (noRepetidos4 ([1..1000] ++ [500..600000]))
--    599499
--    (2.19 secs, 1,459,836,336 bytes)
--    λ> length (noRepetidos5 ([1..1000] ++ [500..600000]))
--    599499
--    (2.24 secs, 1,493,456,360 bytes)