#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
网友评论