我有以下 NSDictionary 结构:
// level
0 1 2 3
// elements
a1 - b1 - c1 - d111.1
- d111.2
- d111.3
c2 - d112.1
- d112.2
c3 - d113.1
考虑到数据文件将是圆形的2000-5000元素。什么是在3级(a1 = 0)计算仅子项的快速方法?要明确:我不想要包含在计数中:a1,b1,c1-c3,只有d *。
你能用NSPredicate做些什么吗?
还是老式的(但价格昂贵的)for-loop方法(eeks)?
// pseudo-code
count=0
for (a in root)
for (b in a)
for (c in b)
for (d in c)
count++
感谢。
答案 0 :(得分:1)
正如@Hot所说:
int count = 0;
for (NSArray *a in root)
for (NSArray *b in a)
for (NSArray *c in b)
count += c.count;
实际上没有太多的开销可以直接通过最后一级,然后只使用计数。
答案 1 :(得分:1)
使用类别的解决方案。
@implementation NSDictionary (RecursiveCount)
- (NSUInteger)recursiveCount {
return self.allValues.recursiveCount;
}
@end
@implementation NSArray (RecursiveCount)
- (NSUInteger)recursiveCount {
int count = 0;
for (id object in self) {
if ([object isKindOfClass:[NSDictionary class]] || [object isKindOfClass:[NSArray class]]) {
count += [object recursiveCount];
} else {
++count;
}
}
return count;
}
@end
- (void)testRecursiveCount {
NSDictionary *dict = @{
@"key1" : @[@1, @2, @3],
@"key2" : @{@"blah" : @[@[], @1, @[@1, @2]]},
@"key3" : @4,
@"key5" : @[@{@"blah":@[@{@1:@1}]}],
};
XCTAssertEqual(dict.recursiveCount, 8, @"dictionary");
NSArray *array = @[
@[@1, @2, @3],
@{@"blah" : @[@[], @1, @[@1, @2]]},
@4,
@[@{@"blah":@[@{@1:@1}]}],
];
XCTAssertEqual(array.recursiveCount, 8, @"dictionary");
}
答案 2 :(得分:0)
一种方法是使用递归。这种方法并不是最便宜的,但它确实具有灵活性的优势 - 如果结构深度发生变化或在编译时未知。
在伪代码中:
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处返回数组的计数,而不是遍历数组,并在每次迭代时将计数递增1为@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'(又名'unsigned long')“)。