-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal for windows
function(s)
#139
Comments
Tuples are limited to 2 or 3 elements so at most we'd have
Of course, I will defer to @Chadtech if it's worth including in this repo. |
I was also playing around with alternate implementations a few days ago but forgot to comment about it. I haven't done any benchmarking but my intuition is that this implementation will be pretty fast (and is stack safe). windows2 : List a -> List ( a, a )
windows2 list =
case list of
_ :: xs ->
List.map2 Tuple.pair list xs
_ ->
[] Another implementation I liked, mainly for its sleekness, is windows2 : List a -> List ( a, a )
windows2 list =
List.map2 Tuple.pair
list
(List.drop 1 list) Both of these implementations can be extended to implement windows3 : List a -> List ( a, a, a )
windows3 list =
case list of
_ :: ((_ :: ys) as xs) ->
List.map3 (\x y z -> ( x, y, z )) list xs ys
_ ->
[] windows3 : List a -> List ( a, a, a )
windows3 list =
List.map3 (\x y z -> ( x, y, z ))
list
(List.drop 1 list)
(List.drop 2 list) As @prikhi mentioned, we cannot go beyond that since tuples can only contain 2 or 3 elements. There is a trick we could use to push past that limitation though. We can generalize windows4 : (a -> a -> a -> a -> b) -> List a -> List b
windows4 f list =
case list of
_ :: ((_ :: ((_ :: zs) as ys)) as xs) ->
List.map4 f list xs ys zs
_ ->
[] or windows4 : (a -> a -> a -> a -> b) -> List a -> List b
windows4 f list =
List.map4 f
list
(List.drop 1 list)
(List.drop 2 list)
(List.drop 3 list) Should we introduce |
Seems like a good function. I know I have used this function before. I think it would be a good idea to include it.
|
Thanks for the discussion, everyone! Replies to QuestionsTo answer @Chadtech's questions:
My use case was for interpolating between adjacent elements. This way, I was turning a list of To be more specific, I wanted to create a discrete color gradient with tiles of colors. I had specific colors in a grid but wanted to add several rows and columns between the original colors. I did some simple math to interpolate a gradient between the colors in the original list to achieve a "blend" from one color to the next. In order to do that, I needed a
I would agree. I think the most common use case is adjacent elements.
My understanding was that it was a "sliding window" across the original list. So yes, it was a different "view" into the original list. The term "sliding window algorithm" is an identical concept, although apparently generic over the size of the window. The term "sliding window" in the "sliding window protcol" is a somewhat similar use of the word "window", although admittedly not exactly identical. Additional DiscussionsOne thing I'm considering more after coming back to this issue is perhaps to have two different functions: a pairs : List a -> List ( a, a )
pairs list =
case list of
_ :: xs ->
List.map2 Tuple.pair list xs
_ ->
[]
windows : Int -> Lis a -> List (List a)
windows length list
if List .length list < length
then
[]
else
List.take length list :: Maybe.withDefault [] (Maybe.map (windows length) (List.tail list))
My style isn't very good for this version of the Any thoughts on having both? I think that the |
Another great use case are rolling averages. Although I think a more flexible signature would be: windows : { leading : Int, trailing : Int } -> (List a -> b -> b) -> b -> List a -> b Since a lot of the cases include potentially heavy data lifting tasks, I think not materialising the list and using it as a fold makes a lot of sense. For instance, if want a 7 day rolling average on an hourly dataset of 1000 points, the intermediate list would have 168000 elements in it. Having two ints (leading and trailing) is useful, since what you want to window around depends on the use case, and sometimes you want to center on the datapoint, other times you want to only use past data. |
A task I occasionally reach for is the ability to iterate through a list in a sliding window to get successive pairs of neighboring elements.
Would we consider adding a
windows
function?Since it may be desirable to have windows of larger sizes, we could name this function
windows2
and add functionswindows3
,windows4
, etc.This is similar to Ruby's
each_slice
function or Rust'swindows
, but returning tuples instead of lists.P.S. Feel free to include feedback on code style, I'm still fairly new to Elm.
The text was updated successfully, but these errors were encountered: