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
Enhance Collection with rollingAvegra #6171
Comments
Hi @Ducasse . |
Oh yes, we need that! |
I propose a different implementation. It allows us to use any block (not just average) and does not convert every collection to an SequenceableCollection >> running: aBlock of: aSubsetSize
"This is a generalization of a running average (a.k.a. moving average, rolling average) which allows you to apply any given block to the shifting subsets of a given size.
For example, given a collection #(1 2 3 4 5) and a window size 2, we collect subsets of this collection by starting with first 2 elements and shifting the window 1 element to the right: #((1 2)(2 3)(3 4)(4 5)), then we apply aBlock to each subset and collect the results. For example, if aBlock is [ :subset | subset average ], this will give us #(1.5 2.5 3.5 4.5)"
| result |
aSubsetSize > self size ifTrue: [
SubscriptOutOfBounds
signal: 'The subset size can not exceed the size of a collection' ].
aSubsetSize < 0 ifTrue: [
SubscriptOutOfBounds
signal: 'The subset size must be positive' ].
result := (1 to: self size - aSubsetSize + 1) collect: [ :i |
aBlock value: (self copyFrom: i to: i + aSubsetSize - 1) ].
^ self species withAll: result SequenceableCollection >> runningAverage: aSubsetSize
"Running average (a.k.a. moving average, rolling average). See the comment of self >> #running:of: for more information."
"(#(1 1 2 2 3 3) runningAverage: 2) >>> {1 . (3/2) . 2 . (5/2) . 3}"
^ self running: #average of: aSubsetSize SequenceableCollection >> runningMin: aSubsetSize
"Running min. See the comment of self >> #running:of: for more information."
"(#(1 1 2 2 3 3) runningMin: 3) >>> {1 . 1 . 2 . 2}"
^ self running: #min of: aSubsetSize SequenceableCollection >> runningMax: aSubsetSize
"Running max. See the comment of self >> #running:of: for more information."
"(#(1 1 2 2 3 3) runningMax: 3) >>> {2 . 2 . 3 . 3}"
^ self running: #max of: aSubsetSize CollectionArithmeticTest >> testRunningAverage
| result collection |
collection := #(1 1 2 2 3 3).
result := collection runningAverage: 2.
self assert: result equals: {1 . (3/2) . 2 . (5/2) . 3}. CollectionArithmeticTest >> testRunningMin
| result collection |
collection := #(1 1 2 2 3 3).
result := collection runningMin: 3.
self assert: result equals: {1 . 1 . 2 . 2}. CollectionArithmeticTest >> testRunningMax
| result collection |
collection := #(1 1 2 2 3 3).
result := collection runningMax: 3.
self assert: result equals: {2 . 2 . 3 . 3}. CollectionArithmeticTest >> testRunningAverageSubscriptOutOfBounds
| collection |
collection := #(1 1 2 2 3 3).
self should: [ collection runningAverage: 7 ] raise: SubscriptOutOfBounds.
self should: [ collection runningAverage: -2 ] raise: SubscriptOutOfBounds. CollectionArithmeticTest >> testRunningAverageWithSubsetSize1IsSameAsCollection
| collection |
collection := #(1 1 2 2 3 3).
self
assert: (collection runningAverage: 1)
equals: collection. CollectionArithmeticTest >> testRunningAverageWithFullSubsetSizeIsSameAsAverage
| collection |
collection := #(1 1 2 2 3 3).
self
assert: (collection runningAverage: collection size)
equals: { collection average }. |
Expected behavior
Like that we can have rolling average :)
Expected development cost
Nearly none just turn the following code into a PR.
The text was updated successfully, but these errors were encountered: