M.J.K M.J.K - 22 days ago 7
Objective-C Question

Sort NSDictionary first by value then by key

So I have a NSNumber dictionary similar to this (keys already added in order):

1 : @2000,
2 : @2000,
4 : @1000,
5 : @1000,
6 : @3000


And I want both values and keys to be sorted in ascending order with the order of the values having the higher priority. (Resulting ordered keys and values being in separate arrays of course as dictionaries aren't ordered as mentioned by @rmaddy).
Result should be:

4 : 1000,
5 : 1000,
1 : 2000,
2 : 2000,
6 : 3000


I can already get the keys sorted by value using

NSArray<NSNumber *> *sortedKeys = [dict keysSortedByValueUsingSelector:@selector(compare:)];


but this doesn't respect the order of the keys of course.

Disclaimer: The solution to this problem in Swift is already given here but I can't figure out how to implement that in Obj-C

Answer

I'd start with a data structure that is sortable:

NSDictionary *d = @{@1 : @2000,
                    @2 : @2000,
                    @4 : @1000,
                    @5 : @1000,
                    @6 : @3000};

NSMutableArray *array = [[NSMutableArray alloc] init];
for (id key in [d allKeys]) {
    [array addObject:@[key, d[key]]];
}

That will give us:

@[ @[@6, @3000], @[@2, @2000], ...]

Now, we can write a comparator that compares however you like. What I understand from the OP is that we want the primary sort on value with a secondary (tie-breaking) sort on keys:

[array sortUsingComparator:^NSComparisonResult(id elementA, id elementB) {
    NSNumber *valueA = ((NSArray *)elementA)[1];
    NSNumber *valueB = ((NSArray *)elementB)[1];
    if ([valueA isEqualToNumber:valueB]) {
        NSNumber *keyA = ((NSArray *)elementA)[0];
        NSNumber *keyB = ((NSArray *)elementB)[0];
        return [keyA compare:keyB];
    } else {
        return [valueA compare:valueB];
    }
}];

NSLog(@"%@", array);