使用计数索引对数组进行排序

时间:2012-12-14 03:49:54

标签: iphone objective-c ios xcode nsarray

我有以下问题:我有一个整数数组,我想将它们放在一个数据结构中,每个整数都包含其出现次数,然后按出现次数排序。

所以,如果我有:

[1, 3, 4, 6, 6, 3, 1, 3]

我会:

[(4,1), (6,2), (1,2), (3,3)]

其中(x,y)==(整数,其出现次数)。

我尝试使用NSCountedSet,但效果不好,我想知道最好的方法是什么。

到目前为止,我已完成以下工作:

NSCountedSet *totalSet = [[NSCountedSet alloc] initWithArray:finalArray];

其中finalArray是完整原始数据未排序的最终数组。 totalSet分为(x,y)但未排序(理想情况下,应按'y'排序)。

我也试过这样做,但它不起作用:

NSArray *sortedArray = [finalArray sortedArrayUsingSelector:@selector(compare:)];

然后做:

NSCountedSet *totalSet = [[NSCountedSet alloc] initWithArray:finalArray];

但这并没有改变'totalSet'。

3 个答案:

答案 0 :(得分:4)

首先,让我们定义一个方便的元组类型,我们可以用它来将数字与其出现次数相关联:

@interface Pair : NSObject
@property(nonatomic, strong) id key;
@property(nonatomic, strong) id value;
- (id)initWithKey:(id)key value:(id)value;
@end

@implementation Pair
- (id)initWithKey:(id)key value:(id)value;
{
    if((self = [super init])) {
        _key = key;
        _value = value;
    }
    return self;
}
- (NSString *)description
{
    return [NSString stringWithFormat:@"(%@,%@)", self.key, self.value];
}
@end

然后,要获得所需的结果,请使用计数集来计算出现次数,然后将结果填充到元组数组中,并按出现次数排序。

- (void)testOccurrenceCounting
{
    NSArray *numbers = @[@1, @3, @4, @6, @6, @3, @1, @3];
    NSCountedSet *set = [[NSCountedSet alloc] initWithArray:numbers];
    NSMutableArray *counters = [NSMutableArray arrayWithCapacity:[set count]];
    [set enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
        [counters addObject:[[Pair alloc] initWithKey:obj value:@([set countForObject:obj])]];
    }];
    [counters sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"value" ascending:YES]]];

    NSLog(@"%@", counters);
}

counters现在是Pair个对象的排序数组,其中key属性包含数字,value属性包含出现次数,两者都装箱为NSNumbers。从那里,您可以取消装箱或根据需要操纵集合。

作为证明这是有效的,这是NSLog陈述的输出:

(
    "(4,1)",
    "(6,2)",
    "(1,2)",
    "(3,3)"
)

答案 1 :(得分:3)

您可以将数字及其计数放入字典数组中,如下所示:

    NSArray *arr = @[@1, @3, @4, @6, @6, @3, @1, @3];
    NSCountedSet *totalSet = [NSCountedSet setWithArray:arr];
    NSMutableArray *dictArray = [NSMutableArray array];
    for (NSNumber *num in totalSet) {
        NSDictionary *dict = @{@"number":num, @"count":@([totalSet countForObject:num])};
        [dictArray addObject:dict];
    }
    NSArray *final = [dictArray sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"number" ascending:YES ]]];
    NSLog(@"%@",final);

答案 2 :(得分:2)

这是我的答案版本。如果您不想使用自定义类,并希望将它们作为单独的数组排序,按照其出现次数的顺序排序,您可以尝试这样做。

创建一个这样的函数,

NSInteger countedSort(id obj1, id obj2, void *context) {
    NSCountedSet *countedSet = (__bridge NSCountedSet *)(context);
    NSUInteger obj1Count = [countedSet countForObject:obj1];
    NSUInteger obj2Count = [countedSet countForObject:obj2];

    if (obj1Count < obj2Count) return NSOrderedAscending;
    else if (obj1Count > obj2Count) return NSOrderedDescending;
    return NSOrderedSame;
}

并使用此,

    NSArray *finalArray = @[@1, @3, @4, @6, @6, @3, @1, @3];    
    NSCountedSet *totalSet = [[NSCountedSet alloc] initWithArray:finalArray];
    NSArray *sortedBasedOnCountArray = [[totalSet allObjects] sortedArrayUsingFunction:countedSort context:(__bridge void *)(totalSet)];
    NSLog(@"sortedObjectsBasedOnCountArray = %@", sortedBasedOnCountArray);

    NSMutableArray *countArray = [NSMutableArray arrayWithCapacity:[sortedBasedOnCountArray count]];

    for (id object in sortedBasedOnCountArray) {
        [countArray addObject:[NSNumber numberWithInt:[totalSet countForObject:object]]];
    }
    NSLog(@"countArray = %@", countArray);

<强>输出:

sortedObjectsBasedOnCountArray = (
    4,
    6,
    1,
    3
)

countArray = (
    1,
    2,
    2,
    3
)

请注意,两个数组按相同顺序排序,数组索引可用于链接它们。

同时检查此NSBag实施。