Andrei Filip
Andrei Filip

Reputation: 1153

NSArray sorted by function

I have an NSArray containing several NSDictionary instances. Each NSDictionary has, among other fields, an object named rating and one numberOfVotes(both are int). How can I sort the array so it gets sorted by rating/numberOfVotes? More generically, can I sort it by doing an operation like mentioned above? Or would it be better to just add another object to each NSDictionary with the value of each operation and then sort by that?

Thanks

EDIT - I have added the following. Still not sorting properly. One question: Should this work for more than 2 objects in my array. (The number of objects will vary)

    [sortedArray sortedArrayUsingComparator:^NSComparisonResult(id dict1, id dict2)
{
    MyObj *obj1 = (MyObj *)dict1;
    MyObj *obj2 = (MyObj *)dict2;

    int rating1 = obj1.rating.intValue;
    int rating2 = obj2.rating.intValue;

    int number1 = obj1.number_of_votes.intValue;
    int number2 = obj2.number_of_votes.intValue;

    double key1 = ((double)rating1)/number1;
    double key2 = ((double)rating2)/number2;

    if (key1 < key2)
    {
        return NSOrderedDescending;
    }

    if (key2 < key1)
    {
        return NSOrderedAscending;
    }
    return NSOrderedSame;

}];

Upvotes: 2

Views: 1045

Answers (7)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726909

You can define a custom comparator to use a composite sorting key of the kind that you are looking for. If there is no good reason to have that sorting key in the dictionary, other than performing the sort, do not add an item to the dictionary.

array = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
    int rating1 = [[obj1 objectForKey:@"rating"] intValue];
    int numberOfVotes1 = [[obj1 objectForKey:@"numberOfVotes"] intValue];
    int rating2 = [[obj2 objectForKey:@"rating"] intValue];
    int numberOfVotes2 = [[obj2 objectForKey:@"numberOfVotes"] intValue];
    double key1 = ((double)rating1)/numberOfVotes1;
    double key2 = ((double)rating2)/numberOfVotes2;
    if (key1 > key2) {
        return (NSComparisonResult)NSOrderedDescending;
    }

    if (key1 < key2) {
        return (NSComparisonResult)NSOrderedAscending;
    }
    return (NSComparisonResult)NSOrderedSame;
}];

Note: The sortedArrayUsingComparator: method does not sort the array in place; instead, it returns a sorted copy. If you would like an in-place sorting, use NSMutableArray.

Upvotes: 4

Bond
Bond

Reputation: 328

you can use NSSortDescriptor here for sorting for example your array that containing several NSDictionnaries name is dataArray.

 NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:rating
                            ascending:YES];
 NSArray * keyArrray = [NSArray arrayWithObjects:descriptor, nil];
 NSArray * sortedArray = [dataArray sortedArrayUsingDescriptors:keyArrray];

With the help of NSSortDescriptor we can sort any data type key value pair.

Upvotes: 0

Sulthan
Sulthan

Reputation: 130152

Ideally, you should substitute NSDictionary by a custom object, with properties like rating and numberOfVotes. Then, you could declare a method compare: on this custom object and use as the selector to sort the array.

You can use a block code to sort the objects but abstracting the implementation into a custom object is much cleaner.

Upvotes: 0

Shamsudheen TK
Shamsudheen TK

Reputation: 31311

Filtering data is one of the essential tasks in computing.

You can sort it several ways.

  1. NSPredicate

    You can see examples here

  2. NSSortDescriptor

    You can see examples here

  3. Regular Expressions

  4. Set Operations

  5. Key-Value Coding

Upvotes: 0

BoteRock
BoteRock

Reputation: 477

The adequate way would be using blocks like this

NSArray *sortedArray;

sortedArray = [unsortedArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    float first = [[(NSDictionary*)a objectForKey:@"rating"] floatValue]/
                      [[(NSDictionary*)a objectForKey:@"numberOfVotes"] floatValue];
    float second = [[(NSDictionary*)a objectForKey:@"rating"] floatValue]/
                      [[(NSDictionary*)a objectForKey:@"numberOfVotes"] floatValue];
return [[NSNumber numberWithFloat:first] compare: [NSNumber numberWithFloat:second]];
}];

you may find more ways to compare:

How to sort an NSMutableArray with custom objects in it?

Upvotes: 1

Jesper
Jesper

Reputation: 7615

Edit: If you want to do rating divided by numberOfVotes, you will have to sort by a function or comparator block or replace the dictionary with a model object which has a method to calculate rating / numberOfVotes.

Use NSSortDescriptor.

 NSArray *sorted = [array sortedArrayUsingDescriptors:[NSArray arrayWithObjects:
    [NSSortDescriptor sortDescriptorWithKey:@"rating" ascending:YES],
    [NSSortDescriptor sortDescriptorWithKey:@"numberOfVotes" ascending:YES],
    nil]
 ];

Upvotes: 0

justin
justin

Reputation: 104698

The family of methods you seek are prefixed with sortedArray.

For a function (which is one of multiple options), see: -[NSArray sortedArrayUsingFunction:context:].

Upvotes: 0

Related Questions