Convert NSArray into Array of unique values sorted by frequency in Objective-C or Swift

123 Views Asked by At

I have an array of values where I would like to count the incidence of each unique value and then create a new array of unique value sorted by incidence.

For example, for the Array as follows:

 vals = {0,0,0,2,0,1,2}

I would like to end up with array of {0,2,1} since 0 is the most common value, 2 is the second most common and 1 is the least common. Note, the fact that these are numbers is irrelevant. They could just as easily be strings.

I thought I might be able to use an nssortdescriptor as in:

NSSortDescriptor *sorter = [NSSortDescriptor sortDescriptorWithKey:@"wordCount" ascending:NO];
NSArray *sortedcats = [vals sortedArrayUsingDescriptors:@[sorter]];

However, this is not sorting them by incidence and it also does not filter out duplicates.

Thanks for any suggestions.

1

There are 1 best solutions below

3
Warren Burton On BEST ANSWER

There's a couple of approaches

Convert to a Set/NSSet then sort.

Swift

let vals = [0,0,0,2,0,1,2]
let uniqued = Set(vals).sorted()

That same method would also work with NSSet + NSSortDescriptor in Objective C but obviously a longer line to write.

or a more classic Foundation approach

let nsvals: NSArray = [3,0,0,2,0,1,2]
let nsuniquedAndSorted = nsvals.value(forKeyPath: "@distinctUnionOfObjects.self")

Which is kind of cool as @distinctUnionOfObjects also sorts for free. There's lots of clever key-value tricks in the same vein here.

EDIT

To sort by incidence an approach could be to count the uniques then resort on that basis.

let sortedByIncidence = uniqued
    .map { outer in return (outer, vals.filter({$0 == outer}).count) }
    .sorted { $0.1 > $1.1 }
    .map { $0.0 }