Segmentos de longitud dada
Definir la función
segmentos :: Int -> [a] -> [[a]]
tal que (segmentos n xs) es la lista de los segmentos de longitud n de la lista xs. Por ejemplo,
segmentos 3 [1..5] == [[1,2,3],[2,3,4],[3,4,5]] length (segmentos 3 [1..30000000]) == 29999998
Soluciones
import Data.List (transpose, tails) import Data.List.Split (divvy) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1ª solución: Recursión simple -- ============================== segmentos1 :: Int -> [a] -> [[a]] segmentos1 n xs | length xs < n = [] | otherwise = take n xs : segmentos1 n (tail xs) -- 2ª solución: Comprensión de listas con índices -- ============================================== segmentos2 :: Int -> [a] -> [[a]] segmentos2 n xs = [take n (drop i xs) | i <- [0..length xs - n]] -- 3ª solución: Comprensión de listas con tails -- ============================================ segmentos3 :: Int -> [a] -> [[a]] segmentos3 n xs = [take n t | t <- tails xs, length t >= n] -- 4ª solución: Composición funcional con tails -- ============================================ segmentos4 :: Int -> [a] -> [[a]] segmentos4 n xs = takeWhile (\ys -> length ys == n) (map (take n) (tails xs)) -- 5ª solución: Optimización precalculando el número de segmentos -- ============================================================== segmentos5 :: Int -> [a] -> [[a]] segmentos5 n xs = take (length xs - n + 1) (map (take n) (tails xs)) -- 6ª solución: Recursión con dos punteros -- ======================================= segmentos6 :: Int -> [a] -> [[a]] segmentos6 n xs = aux (drop (n - 1) xs) xs where aux (_:ts) (y:ys) = take n (y:ys) : aux ts ys aux _ _ = [] -- 7ª solución: Usa 'zipWith const' para recortar los segmentos sobrantes -- ====================================================================== segmentos7 :: Int -> [a] -> [[a]] segmentos7 n xs = zipWith const (map (take n) (tails xs)) (drop (n-1) xs) -- 8ª solución: Usando transpose -- ============================= segmentos8 :: Int -> [a] -> [[a]] segmentos8 n xs = takeWhile (\ys -> length ys == n) (transpose (take n (tails xs))) -- 9ª solución: Uso de la librería split -- ====================================== segmentos9 :: Int -> [a] -> [[a]] segmentos9 = flip divvy 1 -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: (Int -> [Int] -> [[Int]]) -> Spec specG segmentos = do it "e1" $ segmentos 3 [1..5] `shouldBe` [[1,2,3],[2,3,4],[3,4,5]] spec :: Spec spec = do describe "def. 1" $ specG segmentos1 describe "def. 2" $ specG segmentos2 describe "def. 3" $ specG segmentos3 describe "def. 4" $ specG segmentos4 describe "def. 5" $ specG segmentos5 describe "def. 6" $ specG segmentos6 describe "def. 7" $ specG segmentos7 describe "def. 8" $ specG segmentos8 describe "def. 9" $ specG segmentos9 -- La verificación es -- λ> verifica -- 9 examples, 0 failures -- Comprobación de equivalencia -- ============================ -- La propiedad es prop_equivalencia :: Positive Int -> [Int] -> Bool prop_equivalencia (Positive n) xs = all (== segmentos1 n xs) [ segmentos2 n xs , segmentos3 n xs , segmentos4 n xs , segmentos5 n xs , segmentos6 n xs , segmentos7 n xs , segmentos8 n xs , segmentos9 n xs ] -- La comprobación es -- λ> quickCheck prop_equivalencia -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> :set +s -- λ> length (segmentos1 3 [1..30000]) -- 29998 -- (2.37 secs, 12,134,184 bytes) -- λ> length (segmentos2 3 [1..30000]) -- 29998 -- (0.04 secs, 8,773,112 bytes) -- λ> length (segmentos3 3 [1..30000]) -- 29998 -- (2.46 secs, 10,933,280 bytes) -- λ> length (segmentos4 3 [1..30000]) -- 29998 -- (0.04 secs, 14,293,000 bytes) -- λ> length (segmentos5 3 [1..30000]) -- 29998 -- (0.02 secs, 8,533,184 bytes) -- λ> length (segmentos6 3 [1..30000]) -- 29998 -- (0.04 secs, 9,013,120 bytes) -- λ> length (segmentos7 3 [1..30000]) -- 29998 -- (0.02 secs, 9,973,176 bytes) -- λ> length (segmentos8 3 [1..30000]) -- 29998 -- (0.05 secs, 19,332,992 bytes) -- λ> length (segmentos9 3 [1..30000]) -- 29998 -- (0.02 secs, 14,773,224 bytes) -- -- λ> length (segmentos2 3 [1..6000000]) -- 5999998 -- (2.08 secs, 1,632,614,640 bytes) -- λ> length (segmentos4 3 [1..6000000]) -- 5999998 -- (2.07 secs, 2,736,614,520 bytes) -- λ> length (segmentos5 3 [1..6000000]) -- 5999998 -- (1.09 secs, 1,584,614,704 bytes) -- λ> length (segmentos6 3 [1..6000000]) -- 5999998 -- (2.09 secs, 1,680,614,640 bytes) -- λ> length (segmentos7 3 [1..6000000]) -- 5999998 -- (0.38 secs, 1,872,614,696 bytes) -- λ> length (segmentos8 3 [1..6000000]) -- 5999998 -- (2.30 secs, 3,744,614,512 bytes) -- λ> length (segmentos9 3 [1..6000000]) -- 5999998 -- (0.66 secs, 2,832,614,688 bytes) -- -- λ> length (segmentos7 3 [1..30000000]) -- 29999998 -- (1.77 secs, 9,360,615,456 bytes) -- λ> length (segmentos9 3 [1..30000000]) -- 29999998 -- (3.17 secs, 14,160,615,448 bytes)