Objective-C:计算类别中对象的有效方法

时间:2012-07-02 20:09:49

标签: objective-c algorithm dictionary

我在一组类别中有一堆对象。我想知道每个类别有多少。

在另一种语言中,我会创建一个字典,然后遍历这些对象,为每个对象增加字典中的相应值。但是,因为我无法在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];
}

有更有效的方法吗?

4 个答案:

答案 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)

如果这是一个很大的浪费时间,你可以:

  • 创建所有唯一类别的数组
  • 使用其计数来创建int类型的C样式数组
  • 匹配每个传入对象的类别,获取数组偏移量,并增加相应的int bucket
  • (根据需要优化类别查找,如果这成为新的瓶颈)

但我当然同意这位评论者的意见,他说,首先要先衡量。

相关问题