NSArray+Block

作者: 御雪飞斐 | 来源:发表于2019-03-25 21:09 被阅读0次
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    @interface NSArray<ObjectType> (Block)
    
    /**
     遍历数组
    
     @param body 遍历操作 block
     */
    - (void)forEach:(void (^)(ObjectType obj))body;
    
    /**
     根据筛选条件筛选数组元素。如:
     
     NSArray <NSNumber*>*nums  = @[@1, @2, @3, @4, @5];
     NSArray <NSNumber*>*evens = [nums select:^BOOL(NSNumber *obj){
        return [obj integerValue] % 2 == 0;
     }];    // evens is [2, 4]
    
     @param where 筛选条件
     @return 筛选后的新数组
     */
    - (nullable NSArray <ObjectType>*)select:(BOOL (^)(ObjectType obj))where;
    
    /**
     按照顺序遍历的方式,根据筛选条件筛选出第一个符合条件的数组元素。
    
     @param where 筛选条件
     @return 选择的元素
     */
    - (nullable ObjectType)selectOne:(BOOL (^)(ObjectType obj))where;
    
    /**
     select 的相反操作,根据指定条件从数组中剔除元素。
    
     @param where 剔除条件
     @return 剔除指定的元素后的数组
     */
    - (nullable NSArray <ObjectType>*)reject:(BOOL (^)(ObjectType obj))where;
    
    /**
     重组元素
    
     @param initial 初始值
     @param body 重组 block
     @return 组合完成后的结果
     */
    - (id)reduce:(id)initial body:(id (^)(id result, ObjectType obj))body;
    
    /**
     将数组元素映射成另外一种类型的元素并包装成新数组。
     注意,如果返回 nil,则对应的元素会被忽略。
    
     @param body 映射逻辑 block
     @return 映射完成后的新数组
     */
    - (NSArray *)flatMap:(nullable id (^)(ObjectType obj))body;
    
    /**
     数组中是否包含符合指定条件的元素
    
     @param where 指定条件
     @return 包含返回 YES, 否则返回 NO.
     */
    - (BOOL)contain:(BOOL (^)(ObjectType obj))where;
    
    @end
    
    
    
    @interface NSArray<ObjectType> (Safe)
    
    - (ObjectType)safe_objectAtIndex:(NSUInteger)index;
    
    @end
    
    @interface NSArray<ObjectType> (Select)
    
    /**
     获取数组组合结果。从给定的数组中选择 n 个元素的组合(无顺序)。
     @param count 指定选择的个数
     @return 结果集合
     */
    - (NSArray <NSArray<ObjectType>*>*)combineWithCount:(NSUInteger)count;
    
    /**
     随机打乱数组的顺序
    
     @return 乱序后的数组
     */
    - (NSArray <ObjectType>*)random;
    
    @end
    
    #import "NSArray+Block.h"
    
    @implementation NSArray (Block)
    
    - (void)forEach:(void (^)(id))body
    {
        for (id element in self) {
            body(element);
        }
    }
    
    - (NSArray <id>*)select:(BOOL (^)(id))where
    {
        __block NSArray *array = @[];
        [self enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (where(obj)) {
                array = [array arrayByAddingObject:obj];
            }
        }];
        if (array.count == 0)
            return nil;
        return array;
    }
    
    - (nullable id)selectOne:(BOOL (^)(id obj))where {
        __block id selectedObj = nil;
        [self enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (where(obj)) {
                selectedObj = obj;
                *stop = YES;
            }
        }];
        return selectedObj;
    }
    
    - (NSArray <id>*)reject:(BOOL (^)(id))where
    {
        return [self select:^BOOL(id obj) {
            return !where(obj);
        }];
    }
    
    - (id)reduce:(id)initial body:(id (^)(id, id))body
    {
        NSParameterAssert(body != nil);
        
        __block id result = initial;
        
        [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            result = body(result, obj);
        }];
        
        return result;
    }
    
    - (NSArray *)flatMap:(id _Nullable (^)(id _Nonnull))body
    {
        NSParameterAssert(body != nil);
        
        NSMutableArray *result = [NSMutableArray arrayWithCapacity:self.count];
        
        [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            id value = body(obj);
            if (value) [result addObject:value];
        }];
        
        return [result copy];
    }
    
    - (BOOL)contain:(BOOL (^)(id))where {
        
        __block BOOL res = NO;
        [self enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if (where(obj)) {
                *stop = YES;
                res = YES;
            }
        }];
        
        return res;
    }
    
    @end
    
    
    
    
    
    @implementation NSArray (Safe)
    
    - (id)safe_objectAtIndex:(NSUInteger)index {
        index = MIN(index, self.count - 1);
        return [self objectAtIndex:index];
    }
    
    @end
    
    
    
    @implementation NSArray (Select)
    
    - (NSArray *)combineWithCount:(NSUInteger)count {
        
        NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];
        NSMutableArray *res = [NSMutableArray array];
        
        // 防止 block 递归调用循环引用
        __block void (^combine)(NSUInteger, NSUInteger, NSUInteger);
        __block __weak void (^weakCombine)(NSUInteger, NSUInteger, NSUInteger);
        
        weakCombine = combine = ^(NSUInteger count, NSUInteger begin, NSUInteger index) {
            if (count == 0) { [res addObject:array.copy]; return; }
            
            for (NSUInteger i = begin; i < self.count; ++i) {
                array[index] = self[i];
                weakCombine(count - 1, i + 1, index + 1);
            }
        };
        combine(count, 0, 0);
        return [res copy];
    }
    
    - (NSArray *)random {
        return [self sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            return arc4random() % 2 == 0 ? NSOrderedAscending : NSOrderedDescending;
        }];
    }
    
    @end
    

    相关文章

      网友评论

        本文标题:NSArray+Block

        本文链接:https://www.haomeiwen.com/subject/ngkivqtx.html