0

I am trying to sort an array by the number of times a given value is present for a given attribute.

To do this, I am using the following code:

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title.@count" ascending:NO];
            NSArray *descriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
            NSArray *sortedArray  = [results sortedArrayUsingDescriptors:descriptors];

However, while the code compiles, at runtime it is giving the error:

'[<__NSCFNumber 0xb00000000004e293> valueForUndefinedKey:]: this class is not key value coding-compliant for the key @count.'

What am I doing wrong?

Edit:

The array in question actually consists of results from a core data fetch as follows:

  self.managedObjectContext = [Model sharedInstance].managedObjectContext;

    [fetchRequest setPredicate:pred];
  //  fetchRequest.resultType = NSDictionaryResultType;
    NSArray<Articles*> *results = [self.managedObjectContext executeFetchRequest:fetchRequest
                                                                error:&error];
        if ([results count]>=1) {
user6631314
  • 1,751
  • 1
  • 13
  • 44
  • Should it be `@"title.count"` ? – DonMag Mar 01 '19 at 20:14
  • same error:this class is not key value coding-compliant for the key count – user6631314 Mar 01 '19 at 21:44
  • Show the code for the objects in your array? – DonMag Mar 01 '19 at 21:49
  • They are custom objects returned from a core data fetch. I also tried returning them as dictionaries and sorting. But perhaps this entire approach is wrong. – user6631314 Mar 01 '19 at 22:06
  • OK - before you try to init the sortDescriptor, do `Articles *obj = (Articles *)results[0];` --- set a breakpoint, and inspect the properties of `obj`. See if it has a property / key that you can use for your sort descriptor. – DonMag Mar 01 '19 at 22:13
  • 1
    Can you give an example of the array with some objects and how you want that sorted? You can just describe the objects' relevant properties or use dictionaries as a stand-in. A sort descriptor's key path is applied to each object in isolation. The result is then compared to the result from another object to establish ordering between the two objects. A sort descriptor can't sort based on the overall content of the collection. Also `@count` is a collection operator. Unless the objects' `title` property is a collection (and it seems it's not), you can't use `@count`. – Ken Thomases Mar 01 '19 at 22:17
  • Not only does `@count` only work on collections, but if memory serves it goes _before_ the thing you want to count, not after it. When I have used `@sum` in bindings it has always been `@sum.amount` rather than `amount.@sum`. – theMikeSwan Mar 01 '19 at 22:20
  • 1
    The order is correct... Just tried it with objects having `@property (strong, nonatomic) NSArray *arr;`. Using `initWithKey:@"arr.@count"` works as desired. – DonMag Mar 01 '19 at 22:32
  • Maybe it works in both orders https://nshipster.com/kvc-collection-operators/ – theMikeSwan Mar 01 '19 at 22:41
  • 1
    According to [the docs](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/CollectionOperators.html), "The right key path, if present, is ignored" for `@count`. – Ken Thomases Mar 01 '19 at 23:59
  • @DonMag there is a valid property title. It can sort by title which groups all the identical titles together but not ranked by how many times they appear. The error occurs when I add count – user6631314 Mar 02 '19 at 17:30
  • 1
    @ken the title property is NSString so I guess it is not a collection. – user6631314 Mar 02 '19 at 17:32
  • It is `title`, not `titles`. If I assume that you follow the naming conventions, `title` is not a collection and `@count` is not applicable. Show the definition of the entity type. – Amin Negm-Awad Mar 02 '19 at 18:47
  • What do you expect as the result of `@count` applied on a string? – Amin Negm-Awad Mar 02 '19 at 18:48
  • I was hoping to sort the array by the number of times a given value is present for title. So if the most common title is "Swift Cookbook", all the managed objects with that in their title attribute come up first. Perhaps this is totally wrong approach. If so, I apologize for wild goose chase. It may be better to use NSSet as in https://stackoverflow.com/questions/24463072/objective-c-how-to-find-the-most-common-string-in-an-array – user6631314 Mar 02 '19 at 23:35

1 Answers1

1

You can use +\[NSSortDescriptor sortDescriptorWithKey:ascending:comparator:\]. That takes a block that can implement any algorithm you want. You can create an NSCountedSet from [results valueForKey:@"title"] before the sort operation and have the comparator block capture that. That way, you have an easy and cheap way to get the count of a given object's title. The issue is how to regenerate that counted set if/when the objects change (if they can).

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154