Ventana deslizante
Definir la función
ventanas :: Int -> Int -> [a] -> [[a]]
tal que (ventanas x y zs)
es la lista de ventanas de zs
de tamaño x
y deslizamiento y
; es decir, listas de x
elementos consecutivos de zs
(salvo, posiblemente, la última que puede ser menor) tales que la diferencia de posiciones entre los primeros elementos de ventanas consecutivas es y
. Por ejemplo,
ventanas 3 2 [5,1,9,2] == [[5,1,9],[9,2]] ventanas 3 3 [5,1,9,2] == [[5,1,9],[2]] ventanas 3 4 [5,1,9,2] == [[5,1,9]] ventanas 4 1 [1..7] == [[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]] ventanas 4 2 [1..7] == [[1,2,3,4],[3,4,5,6],[5,6,7]] ventanas 4 3 [1..7] == [[1,2,3,4],[4,5,6,7]] ventanas 4 4 [1..7] == [[1,2,3,4],[5,6,7]] ventanas 4 5 [1..7] == [[1,2,3,4],[6,7]] ventanas 4 6 [1..7] == [[1,2,3,4],[7]] ventanas 4 7 [1..7] == [[1,2,3,4]] ventanas 4 8 [1..7] == [[1,2,3,4]] ventanas 3 2 "abcdef" == ["abc","cde","ef"] ventanas 3 3 "abcdef" == ["abc","def"] ventanas 3 4 "abcdef" == ["abc","ef"] ventanas 3 5 "abcdef" == ["abc","f"] ventanas 3 6 "abcdef" == ["abc"] ventanas 3 7 "abcdef" == ["abc"] ventanas 1 5 "abcdef" == ["a","f"]
Soluciones
import Data.List (unfoldr) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1º solución -- =========== ventanas1 :: Int -> Int -> [a] -> [[a]] ventanas1 _ _ [] = [] ventanas1 x y zs | length zs <= x = [zs] | otherwise = take x zs : ventanas1 x y (drop y zs) -- 2ª solución -- =========== ventanas2 :: Int -> Int -> [a] -> [[a]] ventanas2 x y zs = aux (length zs) zs where aux _ [] = [] aux n zs' | n <= x = [zs'] | otherwise = take x zs' : aux (n - y) (drop y zs') -- 3ª solución -- =========== ventanas3 :: Int -> Int -> [a] -> [[a]] ventanas3 x y = unfoldr aux where aux [] = Nothing aux xs = Just (ys,zs) where (ys,us) = splitAt x xs zs | null us = [] | otherwise = drop y xs -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: (Int -> Int -> [Int] -> [[Int]]) -> Spec specG ventanas = do it "e1" $ ventanas 4 1 [1..7] `shouldBe` [[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]] it "e2" $ ventanas 4 2 [1..7] `shouldBe` [[1,2,3,4],[3,4,5,6],[5,6,7]] it "e3" $ ventanas 4 3 [1..7] `shouldBe` [[1,2,3,4],[4,5,6,7]] it "e4" $ ventanas 4 4 [1..7] `shouldBe` [[1,2,3,4],[5,6,7]] it "e5" $ ventanas 4 5 [1..7] `shouldBe` [[1,2,3,4],[6,7]] it "e6" $ ventanas 4 6 [1..7] `shouldBe` [[1,2,3,4],[7]] it "e7" $ ventanas 4 7 [1..7] `shouldBe` [[1,2,3,4]] it "e8" $ ventanas 4 8 [1..7] `shouldBe` [[1,2,3,4]] it "e9" $ ventanas 3 2 [5,1,9,2] `shouldBe` [[5,1,9],[9,2]] it "e10" $ ventanas 3 3 [5,1,9,2] `shouldBe` [[5,1,9],[2]] it "e11" $ ventanas 3 4 [5,1,9,2] `shouldBe` [[5,1,9]] spec :: Spec spec = do describe "def. 1" $ specG ventanas1 describe "def. 2" $ specG ventanas2 describe "def. 3" $ specG ventanas3 -- La verificación es -- λ> verifica -- 21 examples, 0 failures -- Equivalencia de las definiciones -- ================================ -- La propiedad es prop_ventanas :: Positive Int -> Positive Int -> [Int] -> Bool prop_ventanas (Positive x) (Positive y) zs = all (== ventanas1 x y zs) [ventanas2 x y zs, ventanas3 x y zs] -- La comprobación es -- λ> quickCheck prop_ventanas -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> length (ventanas1 4 6 [1..10^5]) -- 16667 -- (3.81 secs, 14,199,776 bytes) -- λ> length (ventanas2 4 6 [1..10^5]) -- 16667 -- (0.05 secs, 14,466,488 bytes) -- λ> length (ventanas3 4 6 [1..10^5]) -- 16667 -- (0.03 secs, 22,333,600 bytes) -- -- λ> length (ventanas2 4 6 [1..10^7]) -- 1666667 -- (1.87 secs, 1,387,268,112 bytes) -- λ> length (ventanas3 4 6 [1..10^7]) -- 1666667 -- (1.18 secs, 2,173,935,176 bytes)