Lassen Sie uns zunächst die Fenster erhalten, ohne am Ende über die kurzen besorgniserregend:
import Data.List (tails)
windows' :: Int -> [a] -> [[a]]
windows' n = map (take n) . tails
> windows' 3 [1..5]
[[1,2,3],[2,3,4],[3,4,5],[4,5],[5],[]]
Jetzt wollen wir von den Kurzen loszuwerden, ohne die Länge Überprüfung Von allen.
Da wir wissen, dass sie am Ende sind, könnten wir sie so verlieren:
windows n xs = take (length xs - n + 1) (windows' n xs)
Aber das ist nicht groß, da wir durch xs eine zusätzliche Zeit gehen noch seine Länge zu erhalten. Es funktioniert auch nicht auf unendlichen Listen, die Ihre ursprüngliche Lösung getan hat.
Stattdessen lassen Sie uns für die Verwendung einer Liste als Lineal eine Funktion schreiben, um die Menge zu messen, von anderen zu nehmen:
takeLengthOf :: [a] -> [b] -> [b]
takeLengthOf = zipWith (flip const)
> takeLengthOf ["elements", "get", "ignored"] [1..10]
[1,2,3]
Jetzt haben wir dieses schreiben kann:
windows :: Int -> [a] -> [[a]]
windows n xs = takeLengthOf (drop (n-1) xs) (windows' n xs)
> windows 3 [1..5]
[[1,2,3],[2,3,4],[3,4,5]]
Arbeiten auf unendliche Listen zu :
> take 5 (windows 3 [1..])
[[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7]]
Wie Gabriel Gonzalez sagt, ist die Zeit Komplexität nicht besser, wenn Sie wollen benutze das ganze Ergebnis. Aber wenn Sie nur einige der Fenster verwenden, schaffen wir es jetzt, die Arbeit von take
und length
auf denen zu vermeiden, die Sie nicht verwenden.
oder 'foldr (zipWith (:)) (Wiederholung []). nehmen m . Schwänze. –
@Will Ness - oh, das ist schön – user1441998
@ user1441998 das ist genau das, was die 'sequenceA' auf' ZipList 'tut. :) (durch „oder“ Ich meinte, „oder es kann geschrieben als explizit ...“). ['sequenceA'] (http://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Traversable.html#sequenceA) == [' foldr ((<*>). ((:) <$>)) (pure []) '] (http://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Traversable.html#line-177). –