Sorting an array with each element contains an NSString and an NSNumber (double) entry

75 Views Asked by At

I created a NSMutableArray with two elements; the name of a city (string at index 0) and the distance (double at index 1) from my present position.

for (i=0;i<[City count];++i)
{
distanceFromMe = [Location distanceFromLocation:[cityLocation]];
[a addObject:[cityNames objectatIndex:i]];
[a addObject:@(distanceFromMe)]
[cityArray addObject:a]
}

"Chicago", 560.34

"New York", 204.3456

"Syracuse", 50.04

I would like to sort this array by ascending distances.

"Syracuse", 50.04

"New York", 204.3456

"Chicago", 560.34

I used:

[cityArray sortUsingDescriptors:@[ [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES] ]];

But I keep getting an error of an unrecognized selector sent to instance. In my reading it appears that the method does not need a key since there is only one NSNumber in the array element. I've read a number of different threads on this but none seem to apply.

Any help would be appreciated. Using xcode obj-c not swift.

2

There are 2 best solutions below

0
bbum On BEST ANSWER

While @JWWalker's solution works, I'd suggest modeling this a little bit differently.

Specifically, create a class to hold the city/distance pairs:

@interface CityDistance
@property(copy) NSString *name;
@property(copy) NSNumber *distance;
@end

@implementation CityDistance
@end

Store each of your city/distance pairs.

CityDistance *cityDistance = [[CityDistance alloc] init];
cityDistance.name = @"New York";
cityDistance.distance = @(560.3);

NSMutableArray <CityDistance *>*cities = [NSMutableArray array];
[cities addObject: cityDistance];

This allows the compiler to do more type checking, you can hang business logic off the class (i.e. maybe a -(NSNumber *)distanceFromCity:(CityDistance *)otherCity; method?), it is less fragile (oops! Forgot to add the distance to my ambiguous array!) and makes the sorting code more clear:

[cityArray sortUsingComparator:
    ^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        CityDistance* city1 = obj1;
        CityDistance* city2 = obj2;
        return [city1.name compare: city2.name];
    }];
0
JWWalker On

I'd do it without using a sort descriptor.

[cityArray sortUsingComparator:
    ^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        NSArray* arr1 = obj1;
        NSArray* arr2 = obj2;
        return [arr1[1] compare: arr2[1]];
    }];