Elementos que respetan la ordenación
Se dice que un elemento x de una lista xs respeta la ordenación si x es mayor o igual que todos lo que tiene delante en xs y es menor o igual que todos lo que tiene detrás en xs. Por ejemplo, en la lista lista [3,2,1,4,6,5,7,9,8] el número 4 respeta la ordenación pero el número 5 no la respeta (porque es mayor que el 6 que está delante).
Definir la función
1 |
respetuosos :: Ord a => [a] -> [a] |
tal que (respetuosos xs) es la lista de los elementos de xs que respetan la ordenación. Por ejemplo,
1 2 3 4 5 6 7 |
respetuosos [3,2,1,4,6,4,7,9,8] == [4,7] respetuosos [2,1,3,4,6,4,7,8,9] == [3,4,7,8,9] respetuosos "abaco" == "aco" respetuosos "amor" == "amor" respetuosos "romanos" == "s" respetuosos [1..9] == [1,2,3,4,5,6,7,8,9] respetuosos [9,8..1] == [] |
Comprobar con QuickCheck que para cualquier lista de enteros xs se verifican las siguientes propiedades:
- todos los elementos de (sort xs) respetan la ordenación y
- en la lista (nub (reverse (sort xs))) hay como máximo un elemento que respeta la ordenación.
Soluciones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
import Data.List (inits, nub, sort, tails) import Test.QuickCheck -- 1ª definición (por comprensión): respetuosos :: Ord a => [a] -> [a] respetuosos xs = [z | k <- [0..n-1] , let (ys,z:zs) = splitAt k xs , all (<=z) ys , all (>=z) zs] where n = length xs -- 2ª definición (por recursión): respetuosos2 :: Ord a => [a] -> [a] respetuosos2 xs = aux [] [] xs where aux zs _ [] = reverse zs aux zs ys (x:xs) | all (<=x) ys && all (>=x) xs = aux (x:zs) (x:ys) xs | otherwise = aux zs (x:ys) xs -- 3ª definición respetuosos3 :: Ord a => [a] -> [a] respetuosos3 xs = [ x | (ys,x,zs) <- zip3 (inits xs) xs (tails xs) , all (<=x) ys , all (x<=) zs ] -- 4ª solución respetuosos4 :: Ord a =>[a] ->[a] respetuosos4 xs = [x | (a, x, b) <- zip3 (scanl1 max xs) xs (scanr1 min xs) , a <= x && x <= b] -- Comparación de eficiencia -- λ> length (respetuosos [1..3000]) -- 3000 -- (3.31 secs, 1,140,407,224 bytes) -- λ> length (respetuosos2 [1..3000]) -- 3000 -- (2.85 secs, 587,082,160 bytes) -- λ> length (respetuosos3 [1..3000]) -- 3000 -- (2.12 secs, 785,446,880 bytes) -- λ> length (respetuosos4 [1..3000]) -- 3000 -- (0.02 secs, 0 bytes) -- 1ª propiedad prop_respetuosos1 :: [Int] -> Bool prop_respetuosos1 xs = respetuosos (sort xs) == sort xs -- La comprobación es -- λ> quickCheck prop_respetuosos1 -- +++ OK, passed 100 tests. -- La 2ª propiedad prop_respetuosos2 :: [Int] -> Bool prop_respetuosos2 xs = length (respetuosos (nub (reverse (sort xs)))) <= 1 -- La comprobación es -- λ> quickCheck prop_respetuosos2 -- +++ OK, passed 100 tests. |
De hecho, dado que en una posición sólo hay un único elemento, cuando se cumple la condición el mínimo y el máximo coinciden luego puede simplificarse (aunque apenas hay optimización) a: