Elemento común en la menor posición
Definir la función
elemento :: Eq a => [a] -> [a] -> [a]
tal que (elemento xs ys) es la lista formada por el elemento común a xs e ys con la menor posición global (considerando su posición en ambas listas). Por ejemplo.
elemento [3,7,6,9,8,0] [5,4,2,7,8,6,9] == [7] elemento [3,7,6,9] [9,5,6] == [9] elemento [5,3,6] [7,6,3] == [3] elemento [0,1,3] [3,1] == [3] elemento [0,3,2] [1,2,3] == [3] elemento [3,7,6,3,8,0] [5,4,9,1,4,2,1] == [] elemento [2,3,5] [7,4] == []
Nota: Como se observa en el 3ª ejemplo, en el caso de que un elemento x de xs pertenezca a ys y el elemento de ys en la misma posición que x pertenezca a xs, se elige como el de menor posición el de xs.
Soluciones
import Data.List (elemIndex, intersect) import Data.Maybe (fromJust) import qualified Data.Set as S import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1ª solución -- =========== elemento1 :: Eq a => [a] -> [a] -> [a] elemento1 xs ys | null zs = [] | m <= n = [x] | otherwise = [y] where zs = interseccion xs ys (m,x) = head [(m',x') | (m',x') <- zip [0..] xs, x' `elem` ys] (n,y) = head [(n',y') | (n',y') <- zip [0..] ys, y' `elem` xs] -- (interseccion xs ys) es la lista de los elementos comunes de xs e -- ys. Por ejemplo, -- interseccion [3,7,6,9] [9,5,6] == [6,9] interseccion :: Eq a => [a] -> [a] -> [a] interseccion xs ys = [x | x <- xs, x `elem` ys] -- 2ª solución -- =========== elemento2 :: Eq a => [a] -> [a] -> [a] elemento2 xs ys | null zs = [] | m <= n = [x] | otherwise = [y] where zs = xs `intersect` ys (m,x) = head [(m',x') | (m',x') <- zip [0..] xs, x' `elem` zs] (n,y) = head [(n',y') | (n',y') <- zip [0..] ys, y' `elem` zs] -- 3ª solución -- =========== elemento3 :: Eq a => [a] -> [a] -> [a] elemento3 xs ys | null zs = [] | m <= n = [x] | otherwise = [y] where zs = xs `intersect` ys x = head [x' | x' <- xs, x' `elem` zs] y = head [y' | y' <- ys, y' `elem` zs] m = fromJust (elemIndex x xs) n = fromJust (elemIndex y ys) -- 4ª solución -- =========== elemento4 :: Eq a => [a] -> [a] -> [a] elemento4 (x:xs) q@(y:ys) | x `elem` q = [x] | y `elem` xs = [y] | otherwise = elemento4 xs ys elemento4 _ _ = [] -- 5ª solución -- =========== elemento5 :: Eq a => [a] -> [a] -> [a] elemento5 [] _ = [] elemento5 (x:xs) ys | x `elem` ys = [x] | otherwise = elemento5 ys xs -- 6ª solución -- =========== elemento6 :: Ord a => [a] -> [a] -> [a] elemento6 xs ys | S.null zs' = [] | m <= n = [x] | otherwise = [y] where xs' = S.fromList xs ys' = S.fromList ys zs' = xs' `S.intersection` ys' (m,x) = head [(m',x') | (m',x') <- zip [0..] xs, x' `S.member` zs'] (n,y) = head [(n',y') | (n',y') <- zip [0..] ys, y' `S.member` zs'] -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: ([Int] -> [Int] -> [Int]) -> Spec specG elemento = do it "e1" $ elemento [3,7,6,9,8,0] [5,4,2,7,8,6,9] `shouldBe` [7] it "e2" $ elemento [3,7,6,9,8,0] [5,4,9,1,8,0,1] `shouldBe` [9] it "e3" $ elemento [3,7,6,3,8,0] [5,4,9,1,4,2,1] `shouldBe` [] it "e4" $ elemento [0,1,3] [3,1] `shouldBe` [3] it "e5" $ elemento [0,3,2] [1,2,3] `shouldBe` [3] spec :: Spec spec = do describe "def. 1" $ specG elemento1 describe "def. 2" $ specG elemento2 describe "def. 3" $ specG elemento3 describe "def. 4" $ specG elemento4 describe "def. 5" $ specG elemento5 describe "def. 6" $ specG elemento6 -- La verificación es -- λ> verifica -- 30 examples, 0 failures -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_equivalencia :: [Int] -> [Int] -> Bool prop_equivalencia xs ys = all (== elemento1 xs ys) [elemento2 xs ys, elemento3 xs ys, elemento4 xs ys, elemento5 xs ys, elemento6 xs ys] -- La comprobación es -- λ> quickCheck prop_equivalencia -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> elemento1 [1..20000] [30000,29999..20000] -- [20000] -- (4.59 secs, 10,203,952 bytes) -- λ> elemento2 [1..20000] [30000,29999..20000] -- [20000] -- (3.27 secs, 10,362,384 bytes) -- λ> elemento3 [1..20000] [30000,29999..20000] -- [20000] -- (3.23 secs, 5,802,840 bytes) -- λ> elemento4 [1..20000] [30000,29999..20000] -- [20000] -- (1.69 secs, 4,601,152 bytes) -- λ> elemento5 [1..20000] [30000,29999..20000] -- [20000] -- (1.68 secs, 5,081,200 bytes) -- λ> elemento6 [1..20000] [30000,29999..20000] -- [20000] -- (0.03 secs, 17,862,792 bytes) -- -- λ> elemento1 [1..10000] ([20000..30000] ++ [5000]) -- [5000] -- (1.87 secs, 6,001,976 bytes) -- λ> elemento2 [1..10000] ([20000..30000] ++ [5000]) -- [5000] -- (1.78 secs, 6,361,936 bytes) -- λ> elemento3 [1..10000] ([20000..30000] ++ [5000]) -- [5000] -- (1.63 secs, 4,082,304 bytes) -- λ> elemento4 [1..10000] ([20000..30000] ++ [5000]) -- [5000] -- (0.66 secs, 3,480,280 bytes) -- λ> elemento5 [1..10000] ([20000..30000] ++ [5000]) -- [5000] -- (0.62 secs, 3,720,272 bytes) -- λ> elemento6 [1..10000] ([20000..30000] ++ [5000]) -- [5000] -- (0.04 secs, 7,169,440 bytes) -- -- λ> elemento4 [1..2000000] ([3000000..5000000] ++ [1]) -- [1] -- (0.16 secs, 256,598,232 bytes) -- λ> elemento5 [1..2000000] ([3000000..5000000] ++ [1]) -- [1] -- (0.29 secs, 256,598,272 bytes) -- λ> elemento6 [1..2000000] ([3000000..5000000] ++ [1]) -- [1] -- (1.77 secs, 1,104,618,904 bytes)