Last active
August 29, 2015 14:16
-
-
Save vy-let/224301c5ac64fd1aee3e to your computer and use it in GitHub Desktop.
Bringing the sliding window metaphor to RACStreams (RACSequences, RACSignals, etc).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RACStream+SlidingWindow.m | |
// Bringing the sliding window stream metaphor to RACStreams (RACSequences, RACSignals, etc). | |
// Copyright © 2015 Talus Baddley. MIT License. | |
// | |
// This is heavily UNTESTED. Please contact me if you find bugs. | |
// | |
#import <ReactiveCocoa/ReactiveCocoa.h> | |
@interface RACStream (SlidingWindow) | |
// | |
// Takes a sliding window of the receiver, with as many as <size> elements, | |
// but no fewer than <minCount> elements. Each element in the stream is an NSArray. | |
// | |
// For instance, the sequence | |
// --(1)--(2)----(3)------(4)------(5)------ | |
// with size 3 and minimum 2, produces arrays | |
// -------[1,2]--[1,2,3]--[2,3,4]--[3,4,5]-- | |
// | |
- (instancetype)slidingWindowSized:(NSUInteger)size minimumCount:(NSUInteger)minCount; | |
// | |
// Takes a sliding window as above, with no minimum. | |
- (instancetype)slidingWindowSized:(NSUInteger)size; | |
// | |
// Takes a sliding window of the receiver at exactly <size> elements wide. Each element in | |
// the stream is a RACTuple. If there are fewer than <size> elements in the window, nils pad | |
// the head of the tuple. (If there are fewer than <minCount> elements, no tuple is produced.) | |
// | |
// For instance, the sequence | |
// --(1)----------(2)--------(3)------(4)------(5)------ | |
// with size 3 and minimum 1, produces tuples | |
// --[nil,nil,1]--[nil,1,2]--[1,2,3]--[2,3,4]--[3,4,5]-- | |
// | |
- (instancetype)nilPaddedSlidingWindowSized:(NSUInteger)size minimumCount:(NSUInteger)minCount; | |
@end | |
@implementation RACStream (SlidingWindow) | |
- (instancetype)slidingWindowSized:(NSUInteger)size { | |
return [self slidingWindowSized:size minimumCount:0]; | |
} | |
- (instancetype)slidingWindowSized:(NSUInteger)size minimumCount:(NSUInteger)minCount { | |
// Based on https://github.com/baconjs/bacon.js/blob/master/src/slidingwindow.coffee | |
return [[self | |
scanWithStart:@[] reduce:^id(NSArray *running, id next) { | |
NSRange sliceRange = ([running count] >= size ? | |
NSMakeRange(1, size) : | |
NSMakeRange(0, [running count] + 1) | |
); | |
return [[running arrayByAddingObject:next] subarrayWithRange:sliceRange]; | |
}] | |
filter:^BOOL(NSArray *window) { | |
return [window count] >= minCount; | |
}]; | |
} | |
- (instancetype)nilPaddedSlidingWindowSized:(NSUInteger)size minimumCount:(NSUInteger)minCount { | |
return [[self slidingWindowSized:size minimumCount:minCount] | |
map:^id(NSArray *flexWindow) { | |
NSInteger sizeDiff = size - [flexWindow count]; | |
NSMutableArray *buf = [NSMutableArray arrayWithCapacity:size]; | |
for (NSUInteger fuckingManualIteration = 0; fuckingManualIteration < sizeDiff; fuckingManualIteration++) { | |
[buf addObject:[RACTupleNil tupleNil]]; | |
} | |
// Or, as you'd say in Ruby, Array.new(sizeDiff, nil) | |
[buf addObjectsFromArray:flexWindow]; | |
return [RACTuple tupleWithObjectsFromArray:buf]; | |
}]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment