我在一组类别中有一堆对象。我想知道每个类别有多少。
在另一种语言中,我会创建一个字典,然后遍历这些对象,为每个对象增加字典中的相应值。但是,因为我无法在Objective-C中的NSDictionary中存储本机数字类型,所以我不断在NSNumber和数字类型之间来回转换:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
for (MyObject *obj in objs) {
NSNumber *old = [dictionary objectForKey:obj.category];
NSNumber *new = [NSNumber numberWithInteger:1 + old.integerValue];
[dictionary setObject:new forKey:obj.category];
}
有更有效的方法吗?
答案 0 :(得分:6)
您正在寻找NSCountedSet
。
NSCountedSet *bag = [[NSCountedSet alloc] init];
for (MyObject *obj in objs) {
[bag addObject:obj.category];
}
for (id category in bag) {
NSLog(@"%d instances of %@", [bag countForObject:category], category);
}
答案 1 :(得分:1)
您可以使用NSMutableData来存储您的计数器:
int * count;
NSMutableData * num;
NSMutableDictionary * dictionary;
dictionary = [[NSMutableDictionary alloc] init];
for (MyObject *obj in objs)
{
if ((count = [[dictionary objectForKey:obj.category] mutableBytes]) == nil)
{
num = [NSMutableData dataWithCapacity:sizeof(int)];
count = [num mutableBytes];
*count = 0;
[dictionary setObject:num forKey:obj.category];
};
*count += 1;
};
这样可以防止每次更新类别的计数时都会修改字典并分配新的NSNumber
答案 2 :(得分:0)
如果它确实是一个瓶颈,你可以使用底层的CFDictionaryRef而不是NSMutableDictionary来创建一个直接存储整数的字典,而不是用NSNumber值来装箱。
阅读有关CFDictionaryCreateMutable和CFDictionaryValueCallBacks的文档以获取详细信息,但基本思想是您的保留和发布不执行任何操作,您的描述会动态生成NSNumber(或者只是生成一个stringWithFormat:“%d”),并且您的平等直接比较整数。
以下示例显示了代码中棘手的部分:
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
CFStringRef intdesc(const void *value) {
int i = (int)value;
CFNumberRef n = CFNumberCreate(NULL, kCFNumberIntType, &i);
CFStringRef s = CFCopyDescription(n);
CFRelease(n);
return s;
}
Boolean inteq(const void *value1, const void *value2) {
int i1 = (int)value1, i2 = (int)value2;
return i1 == i2;
}
int main(int argc, char *argv[]) {
CFDictionaryValueCallBacks cb = { 0, NULL, NULL, &intdesc, &inteq };
CFMutableDictionaryRef d =
CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&cb);
CFDictionarySetValue(d, @"Key1", (void *)1);
CFDictionarySetValue(d, @"Key2", (void *)2);
CFStringRef s = CFCopyDescription(d);
NSLog(@"%@", s);
CFRelease(s);
CFRelease(d);
return 0;
}
如果你要做很多这样的事情,你应该把它包装在ObjC中(特别是如果你使用的是ARC),但这仍然是读者的练习。
答案 3 :(得分:0)
如果这是一个很大的浪费时间,你可以:
但我当然同意这位评论者的意见,他说,首先要先衡量。