I want to do kind of a weird dictionary sort. I have non-unique values and keys and get something like this
NSArray *counts = [@"1",@"2",@"2",@"3",@"6",@"10"];
NSArray *names =[@"Jerry",@"Marge",@"Jerry",@"Marge",@"Jen",@"Mark"];
The output that I want is an descending ordered list by counts with unique names. I don't want lower values of the same person in my outputted arrays. The output should be.
sortedNames=[@"Mark",@"Jen",@"Marge",@"Jerry"]
sortedCounts=[@"10",@"6",@"3",@"2"];
I would really appreciate some help on this.
NSMutableArray *userNameArray = [[NSMutableArray alloc] init];
NSMutableArray *countArray = [[NSMutableArray alloc] init];
for (NSDictionary *dict in bigDick) {
NSString *nameString =[dict objectForKey:@"Name"];
NSString *countString =[dict objectForKey:@"Count"];
NSInteger countInt = [countString integerValue];
NSNumber *countNumber =[NSNumber numberWithInt:countInt];
[userNameArray addObject:nameString];
[countArray addObject:countNumber];
}
NSArray *namesAscending =[[userNameArray reverseObjectEnumerator]allObjects];
NSArray *countsAscending=[[countArray reverseObjectEnumerator]allObjects];
// Put the two arrays into a dictionary as keys and values
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:countsAscending forKeys:namesAscending];
// Sort the first array
NSArray *sortedCountArray = [[dictionary allValues] sortedArrayUsingSelector:@selector(compare:)];
// Sort the second array based on the sorted first array
// NSArray *sortedNameArray= [dictionary objectsForKeys:sortedCountArray notFoundMarker:[NSNull null]];
NSMutableArray *nameArray =[[NSMutableArray alloc] init];
for (int i=1; i<sortedCountArray.count; i++) {
NSString *name = [dictionary allKeysForObject:sortedCountArray[i]];
if (sortedCountArray[i]!=sortedCountArray[i-1]) {
[nameArray addObject:name];
}
}
Your problem is in your algorithm design, if you step through it a line at a time in the debugger you should see what it does and where it goes wrong.
We're not here to write you code, but let's see if we can go through one step of an algorithm to help you one your way:
Useful fact: If you lookup a key in a dictionary and that key does not exist the return value will be nil
.
From this: you can use a dictionary to keep track of the names you have seen paired with the highest score so far. You obtain a name,score pair, lookup the name in the dictionary - if you get nil
its a new name with a new high score. If it's not nil
its the currently known high score, so you can compare and update.
That's a rough algorithm, let's try it. Before we start rather than using literal strings for keys everywhere let's define some constants. This has the advantage that we won't mistype the strings, the compiler will spot if we mistype the constant names. These can be defined at the file level or within a method:
const NSString *kName = @"Name";
const NSString *kCount = @"Count";
Now to the code, in a method somewhere, we'll need a dictionary:
NSMutableDictionary *highScores = [NSMutableDictionary new]; // a single dictionary rather than your two arrays
Now start your loop as before:
for (NSDictionary *dict in bigDict) // same loop as your code
{
and extract the two values as before:
NSString *nameString = dict[kName]; // same as your code, but using modern syntax
NSInteger countInt = [dict[kCount] integerValue]; // condense two lines of your code into one
Now we can lookup the name in our dictionary:
NSNumber *currentScore = highScores[nameString]; // get current high score for user, if any
If the name exists as a key this will return the current associated value - the score in this case, if there is no matching key this will return nil
. We can test for this in a single if
:
if (currentScore == nil // not seen user before, no high score
|| currentScore.integerValue < countInt) // seen user, countInt is greater
{
The above condition will evaluate to true if we either need to add the name or update its score. Adding & updating a key/value pair is the same operation, so we just need the line:
highScores[nameString] = @(countInt); // add or update score for user
and a couple of braces to terminate the if
and for
:
}
}
Let's see what we have:
NSLog(@"Output: %@", highScores);
This outputs:
Output: {
Jen = 6;
Jerry = 2;
Marge = 3;
Mark = 10;
}
Which is a step in the right direction. (Note: the dictionary is not sorted, NSLog
just displays the keys in sorted order.)
Make sure you understand why that works, copy the code and test it. Then try to design the next phase of the algorithm.
If you get stuck you can ask a new question showing the algorithm and code you've developed and someone will probably help. If you do this you should include a link to this question so people can see the history (and know you're not trying to get an app written for you through multiple questions!)
HTH