Closed robinsenior closed 10 years ago
Any way to distribute this across multiple cores? It was my understanding that parallelism was one of the reasons why the map/reduce pattern was so valuable.
@shepting there is, where -reduce
would be a void method returning stuff in a block.
Otherwise, it might be an interesting problem to solve if the method stays synchronous but internals are async
@robinsenior thank you for the contribution! Does it make sense to add a counterpart with no initial value as well?
-reduce:^{block}
and
reduce:0 withBlock:^{block}
@shepting only if the operations are associative, I believe. I think that operations like foldl can be parallelized because they assume that order of operations does not matter. Operations like division are order dependant and cannot be executed out of order. (see http://stackoverflow.com/questions/329423/parallelizing-the-reduce-in-mapreduce)
@supermarin we could do that, where if you do not explicitly specify an initial value, then the first element of the array/set is used as the initial value.
@robinsenior right, that make sense. let's merge this and i'll add the counterpart without explicit accumulator.
Thanks once again! :beer:
@robinsenior & @supermarin Counterpart without initial can be failed
@zrcoder could you elaborate a bit more by providing an example?
If the initial value is nil
, then the first element is just copied.
For example, the implementation might look like:
for(id object in self)
accumulator = accumulator ? block(accumulator, object) : object;
@zrcoder @supermarin should we also add checking for nil blocks?
I notice this library doesn't do much nil checking or range checking, should it be added throughout?
block = ^NSNumber*(NSNumber* accumulator, id object){
//Assume `add` is categorized and element has value as property
return [accumulator add object.value];
}
Thus, after the first round, accumulator as the first element will be incorrect
@zrcoder sorry - i still don't understand the problem. if you could reproduce it with a whole gist that'd be appreciated.
Since methods in objc are dynamic, the fact that one is categorized should't make any problems as long as the object
responds to it.
@supermarin
@interface Item
@property(nonatomic, strong)NSNumber* value;
+ (instancetype)itemWithValue:(NSNumber*)value;
//Other properties
@end
@interface NSNumber(NumberOnly)
- (NSNumber*)methodAvailableOnNumberButItem:(NSNumber*)number;
@end
NSArray* items = @[[Item itemWithValue:@1],[Item itemWithValue:@2]];
NSNumber* total = [items reduce:^NSNumber*(NSNumber* accumulator, id object){
return [accumulator methodAvailableOnNumberButItem: [object value]];
}
In the block, accumulator is alway expected as a NSNumber
, however it will be Item
if the initial is nil, therefore it (accumulator) won't respond method methodAvailableOnNumberButItem
@zrcoder oh, I see what you're saying.
That shouldn't be a problem, since it's the expected behavior from some other languages as well. In that case you want to use the counterpart with initial value provided.
[items reduce:@0 withBlock:^(NSNumber *accumulator, Item *item){
return [accumulator methodAvailableOnNumberButItem: item.value];
}];
@supermarin My point is the type of accumulator is not homogeneous in all steps of the loop if initial is not provided.
Return a single value from an array or set by iterating through the elements and transforming a running total. Similar to Ruby's reduce method, also known as fold or inject.