Skip to content

Add sliding windows algorithm #20

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

Merged
merged 17 commits into from
Oct 30, 2020
Merged

Conversation

ollieatkinson
Copy link
Contributor

@ollieatkinson ollieatkinson commented Oct 12, 2020

Many thanks to @timvermeulen for helping me refine this collection algorithm.

Description

Break a collection into overlapping contiguous window subsequences where
elements are slices from the original collection.

The slidingWindows(ofCount:) method takes in a integer size and returns a collection of subsequences.

let swift = "swift"

let windowed = swift.slidingWindows(ofCount: 2) 
// windowed == [ "sw", "wi", "if", "ft" ]

Detailed Design

The slidingWindows(ofCount:) is added as a method on an extension of Collection

extension Collection {
  public func slidingWindows(ofCount count: Int) -> SlidingWindows<Self> {
    SlidingWindows(base: self, size: count)
  }
}

If a size larger than the collection length is specified, an empty collection is returned. Due to this
behaviour the indexes must be calculated on initialisation as we have to be able to compare the
upperBound and allow Collection correctly calculate isEmpty .

[1, 2, 3].slidingWindows(ofCount: 5).isEmpty // true

The resulting SlidingWindows type is a collection, with conditional conformance to the
BidirectionalCollection, and RandomAccessCollection when the base collection
conforms.

Complexity

The call to slidingWindows(ofCount: k) is O(1) if the collection conforms to
RandomAccessCollection, otherwise O(k). Access to the next window
is O(1).

Naming

The type SlidingWindows takes its name from the algorithm, similarly the method takes
it's name from it too slidingWindows(ofCount: k).

The label on the method ofCount was chosen to create a consistent feel to the API
available in swift-algorithms repository. Inspiration was taken from
combinations(ofCount:) and permutations(ofCount:).

Previously the name windows was considered but was deemed to potentially create
ambiguity with the Windows operating system.

Comparison with other languages

rust has std::slice::Windows which is a method available on slices. It has the same semantics as
described here.

Documentation

This documentation exists in Guides/SlidingWindows.md

Impact

This is an additive change, no impact.


Checklist

  • I've added at least one test that validates that my change is working, if appropriate
  • I've followed the code style of the rest of the project
  • I've read the Contribution Guidelines
  • I've updated the documentation if necessary

@ollieatkinson ollieatkinson marked this pull request as draft October 12, 2020 19:37
@ollieatkinson ollieatkinson marked this pull request as ready for review October 14, 2020 10:39
@kylemacomber
Copy link

What do you think about windows(ofCount:) rather than windows(size:)?

When we were naming combinations(ofCount:), permutations(ofCount:), and randomSample(count:), we tried to consistently use "count" when it referred to the number of elements in a sequence or collection—avoiding synonyms size and length.

@ollieatkinson
Copy link
Contributor Author

ollieatkinson commented Oct 14, 2020

What do you think about windows(ofCount:) rather than windows(size:)?

When we were naming combinations(ofCount:), permutations(ofCount:), and randomSample(count:), we tried to consistently use "count" when it referred to the number of elements in a sequence or collection—avoiding synonyms size and length.

I would not be against the name change, it was not immediately obvious to me that ofCount was an option. I prefer size but I also prefer consistent API naming.

The arguments you make are valid, so I would be happy to change it - but, before I do, It might be a good idea to see what other folks think first.

Copy link
Member

@natecook1000 natecook1000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution, @ollieatkinson! 👏

@ollieatkinson
Copy link
Contributor Author

@kylemacomber I've given this some thought and renamed the label to ofCount

@xwu
Copy link
Contributor

xwu commented Oct 14, 2020

In a general-purpose language that now has Windows support, I would be wary of a general-purpose API vending a type named Windows. I do think SlidingWindows would be more apt here.

@ollieatkinson
Copy link
Contributor Author

In a general-purpose language that now has Windows support, I would be wary of a general-purpose API vending a type named Windows. I do think SlidingWindows would be more apt here.

That's a good thought, I'm liking the suggestion you've made! Thank you @xwu

@pyrtsa
Copy link

pyrtsa commented Oct 15, 2020

Any reason not to rename the function accordingly now, windows(ofCount:)slidingWindows(ofCount:)?

@ollieatkinson
Copy link
Contributor Author

Any reason not to rename the function accordingly now, windows(ofCount:)slidingWindows(ofCount:)?

I'm in the process of renaming the type, function and updating the documentation now!

Copy link
Member

@natecook1000 natecook1000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, @ollieatkinson!

@natecook1000 natecook1000 merged commit b28d248 into apple:main Oct 30, 2020
@Danappelxx
Copy link

Should probably add a link to Guides/SlidingWindows.md to the README :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants