-
Notifications
You must be signed in to change notification settings - Fork 614
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
feat(collections): add slidingWindows #1191
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only minor comments, well done overall, thanks!
collections/windowed.ts
Outdated
const length = Math.floor((array.length - (partial ? 1 : size)) / step + 1); | ||
|
||
return Array.from( | ||
{ length }, | ||
(_, i) => array.slice(i * step, i * step + size), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this - it is concise, understandable but also not trivial.
collections/windowed.ts
Outdated
const length = Math.floor((array.length - (partial ? 1 : size)) / step + 1); | ||
|
||
return Array.from( | ||
{ length }, | ||
(_, i) => array.slice(i * step, i * step + size), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personal nitpick: When too many things happen on one line, it starts to become hard to read. You could definitely split some value (like the ternary) into their own intermediary const
. That is really just a nitpick though, so don't bother if you do not agree :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, the result of deno fmt
is within single line, so I'd like to leave it as it is.
collections/windowed_test.ts
Outdated
// @ts-ignore: for test | ||
windowed([1, 2, 3, 4, 5], "invalid"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to test for invalid TS calls - if we start doing that, you might as well check every parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we forgot to throw an error here, the length
will be NaN
and we will get the unexpected behavior of returning an empty array. I'd like to leave this test alone to make sure that an error is thrown when passing a non-numeric value.
collections/windowed_test.ts
Outdated
@@ -0,0 +1,220 @@ | |||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very thorough tests overall - thanks!
I found it faster to use the for statement and array.push than to use Array.from, so I modified the code accordingly. Benchmark for arrays of length 10000:
|
collections/windowed.ts
Outdated
/** length of the return array */ | ||
const length = Math.floor((array.length - (partial ? 1 : size)) / step + 1); | ||
|
||
const result = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const result = []; | |
const result = new Array(length); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proposed Thank you.
Sure, new Array(length)
(0.33261830000000053ms) is a bit faster than array.push
(0.36173926999999984ms).
However, according to this V8 blog post, it seems that V8 can optimize the code better with array.push
than with new Array(length)
. I would like to use array.push
to improve the performance of subsequent code that uses the return value of this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are pushing arrays into array, primitive value optimization is impossible in this case (not to mention type hint does not make up for time you waste reallocing memory)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@devcat what @ayame113 is (I think correctly) getting at, is that when you build an Array using the constructor with a length value, you are saving some performance for reallocation when filling it, but that Array is and will forever be markes as HOLEY_
, which prevents v8 from applying performance optimizations to further operations on it like .map()
.
I think this is actually really interesting here and in all the other functions. We have been doing new Array(length)
whenever possible, but thinking about it now, that means that we improve the performance of our function a bit, but return
an unoptimizable HOLEY_
Array to the user that will perform worse in their code. Specifically for bigger Arrays, I don't think that is desirable, as the reallocation impact is only O(log n)
and only happens once, while the impact of the user carrying a HOLEY_
Array through their code happens ok every single further operation on it.
I plan to do a benchmark suite for the whole module as soons as we are API complete, we should investigate that further once that lands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LionC
Thanks for the explanation, that's what I wanted to say. 👍
I found a discussion that took place when I introduced the windowed function to Kotlin. According to it, other names used in other languages or suggested are:
I like |
Something with "sliding" is very good I think. But why only one "window" when it returns multiple? What about |
Oops, I missed this comment before commit 7677fd2. I think |
I would vote strongly for |
Thank you @ayame113 for researching the past discussion in kotlin community. Among 2 candidates, I slightly prefer |
I updated to use the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ayame113 Thank you for updating the name 🙏
LGTM. Nice work!
for #1173