一种方法是使用递归。这种方法不是最便宜的,但它确实具有灵活性的优势——如果结构的深度发生变化或者在编译时是未知的。
在伪代码中:
integer count ( collection , maxDepth )
return recursiveCount ( collection , 0 , maxDepth )
end
integer recursiveCount ( collection , currentDepth , maxDepth )
integer count = 0
if collection is array
count += recursiveCountArray ( collection , currentDepth , maxDepth )
else if object is dictionary
count += recursiveCountDictionary ( collection.values , currentDepth , maxDepth )
else
count += 1
return count
end
integer recursiveCountArray ( array , currentDepth , maxDepth )
integer count = 0
if currentDepth < maxDepth
for ( object in array )
count += recursiveCount( object )
else
count += array.count
return count
end
该maxDepth
参数确保不会完成不必要的工作(只需在 maxDepth 时返回数组的计数,而不是像@RamyAlZuhouri 在他的评论中建议的那样在每次迭代中迭代数组并增加计数)。
在 Objective-C 中,这可以通过 C 函数来实现:
static NSUInteger _PFXRecursiveCount(id collection, NSUInteger currentDepth, NSUInteger maxDepth);
static NSUInteger _PFXRecursiveCountArray(id array, NSUInteger currentDepth, NSUInteger maxDepth);
NSUInteger PFXRecursiveCount(id collection, NSUInteger maxDepth)
{
return _PFXRecursiveCount(collection, 0, maxDepth);
}
NSUInteger _PFXRecursiveCount(id collection, NSUInteger currentDepth, NSUInteger maxDepth)
{
NSUInteger count = 0;
if ([collection isKindOfClass:[NSArray class]]) {
count = _PFXRecursiveCountArray(collection, currentDepth, maxDepth);
} else if ([collection isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = (NSDictionary *)collection;
count = _PFXRecursiveCountArray(dictionary.allValues, currentDepth, maxDepth);
} else {
count = 1;
}
return count;
}
NSUInteger _PFXRecursiveCountArray(NSArray *array, NSUInteger currentDepth, NSUInteger maxDepth)
{
NSUInteger count = 0;
if (currentDepth < maxDepth) {
for (id object in array) {
count += _PFXRecursiveCount(object, currentDepth + 1, maxDepth);
}
} else {
count += array.count;
}
return count;
}
这里PFX
将替换为项目中使用的适当前缀。只会PFXRecursiveCount
在标题中声明。
或者,这可以通过块来实现:
typedef NSUInteger (^RecursiveCountArrayBlock)(NSArray *, NSUInteger, NSUInteger);
typedef NSUInteger (^RecursiveCountBlock)(id, NSUInteger, NSUInteger);
__block __weak RecursiveCountArrayBlock _weakRecursiveCountArray = nil;
__block __weak RecursiveCountBlock _weakRecursiveCount = nil;
NSUInteger (^_recursiveCount)(id, NSUInteger, NSUInteger) = ^(id collection, NSUInteger currentDepth, NSUInteger maxDepth) {
NSUInteger count = 0;
if ([collection isKindOfClass:[NSArray class]]) {
count = _weakRecursiveCountArray(collection, currentDepth, maxDepth);
} else if ([collection isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = (NSDictionary *)collection;
count = _weakRecursiveCountArray(dictionary.allValues, currentDepth, maxDepth);
} else {
count = 1;
}
return count;
};
_weakRecursiveCount = _recursiveCount;
NSUInteger (^_recursiveCountArray)(id, NSUInteger, NSUInteger) = ^(NSArray *array, NSUInteger currentDepth, NSUInteger maxDepth) {
NSUInteger count = 0;
if (currentDepth < maxDepth) {
for (id object in array) {
count += _weakRecursiveCount(object, currentDepth + 1, maxDepth);
}
} else {
count += array.count;
}
return count;
};
_weakRecursiveCountArray = _recursiveCountArray;
NSUInteger (^recursiveCount)(id, NSUInteger) = ^(id collection, NSUInteger maxDepth) {
return _recursiveCount(collection, 0, maxDepth);
};
__weak
__block
变量 (_weakRecursiveCountArray
和_weakRecursiveCount
) 允许我们避免从自身内部对块的强引用。(注意:在 iOS 5 和 10.7 之前,__weak
需要替换为__unsafe_unretained
。) typedef 允许我们避免虚假警告(“'__weak' 仅适用于 Objective-c 对象或块指针类型;这里的类型是 'NSUInteger' (又名'无符号长')”)。