2

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;

}];
Andrei Filip
  • 1,145
  • 15
  • 33

7 Answers7

4

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
1

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?

Community
  • 1
  • 1
BoteRock
  • 467
  • 6
  • 12
0

The family of methods you seek are prefixed with sortedArray.

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

justin
  • 104,054
  • 14
  • 179
  • 226
0

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]
 ];
Jesper
  • 7,477
  • 4
  • 40
  • 57
  • It looks like the OP wants to divide `rating` by the `numberOfVotes`, not resolve conflicts by `numberOfVotes`. – Sergey Kalinichenko Oct 30 '12 at 14:30
  • Ah. Then the OP will have to use a comparator/function (see @dasblinkenlight) or go from a dictionary to a model object and define a method that calculates the appropriate value to rank by. – Jesper Oct 30 '12 at 14:31
0

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

Community
  • 1
  • 1
Shamsudheen TK
  • 30,739
  • 9
  • 69
  • 102
0

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.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
0

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.

Bond
  • 328
  • 4
  • 16