2

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

在另一种语言中,我会制作一个字典,然后遍历对象,为每个对象增加字典中的适当值。但是,因为我不能在 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

4 回答 4

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);
}
于 2012-07-02T20:37:47.230 回答
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每次更新类别的计数时都不会分配新的字典

于 2012-07-02T20:27:59.537 回答
0

如果它确实是一个瓶颈,你可以使用底层的 CFDictionaryRef 而不是 NSMutableDictionary,来创建一个直接存储整数的字典,而不是将它们装箱到 NSNumber 值中。

阅读有关 CFDictionaryCreateMutable 和 CFDictionaryValueCallBacks 的文档以了解详细信息,但基本思想是您的保留和释放什么都不做,您的描述会即时生成一个 NSNumber(或者只是执行 stringWithFormat:"%d"),并且您的 equal 比较整数直接地。

这是一个显示代码中棘手部分的示例:

#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),但这留给读者作为练习。

于 2012-07-02T20:32:03.473 回答
0

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

  • 创建所有唯一类别的数组
  • 使用它的计数来创建一个 C 风格的 int 类型数组
  • 匹配每个传入对象的类别,得到一个数组偏移量,并递增对应的int桶
  • (根据需要优化类别查找,如果这成为新的瓶颈)

但我当然同意评论者所说的,基本上,首先测量。

于 2012-07-02T20:34:53.093 回答