Reputation: 3803
I need to display in a UITableView the content of a NSDictionary returned by an API, respecting the order of the keys.
I'm using :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *key = self.data.allKeys[indexPath.section];
NSArray *list = self.data[key];
id data = list[indexPath.row];
PSSearchCell *cell = [PSSearchCell newCellOrReuse:tableView];
cell.model = data;
return cell;
}
but as I do self.data.allKeys
, I'm loosing the order of my keys. I can't sort them by value as it doesn't concern them.
Upvotes: 11
Views: 18252
Reputation: 432
You said that you were losing the order of the keys, so I suppose you pull those keys from a NSArray
. Right? And in that NSArray
you have the keys ordered as you want. And I also see that the objects of the NSDictionary
are Arrays
, right? Yes. So in your Ordered Array
you have more arrays.
data
is the name of the NSDictionary.
So, all you have to do is to bring that NSArray
(the one that is ordered as you always wanted) into this .m file and after that use some awesome code in your cellForRowAtIndexPath
method. You can do it by doing the following:
@interface yourViewController ()
{
NSArray *yourArrayOrdered;
}
@end
@implementation yourViewController
- (void)viewDidLoad
{
[super viewDidLoad];
yourArrayOrdered = [[NSArray alloc] initWith...:... ];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *key = yourArrayOrdered[indexPath.row];
NSArray *list = [self.data objectForKey:yourArrayOrdered[indexPath.row]];
//your code continues here...
/*id data = list[indexPath.row]; //don't think you need this line
PSSearchCell *cell = [PSSearchCell newCellOrReuse:tableView];
cell.model = data; */
return cell;
}
And this is all you have to do to keep the order you want using a NSDictionary and NSArray.
To visualize it better, in the case that your ordered array only contains strings it would be like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *key = yourArrayOrdered[indexPath.row];
NSString *myString = [self.data objectForKey:yourArrayOrdered[indexPath.row]];
cell.textLabel.text = [NSString stringWithFormat:@"THIS IS THE OBJECT %@", myString];
cell.detailTextLabel.text = [NSString stringWithFormat:@"AND THIS IS THE KEY %@", key];
return cell;
}
Hope it helps.
Upvotes: 0
Reputation: 9836
Try this,
NSArray *keys = [myDictionary allKeys];
keys = [keys sortedArrayUsingComparator:^(id a, id b) {
return [a compare:b options:NSNumericSearch];
}];
NSLog(@"%@",keys);
Now fetch values based on the key sorted.
EDIT
To sort them in alphabetical order try this,
NSArray *keys = [myDictionary allKeys];
keys = [[keys mutableCopy] sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
NSLog(@"%@",keys);
Upvotes: 26
Reputation: 3001
I wrote a quick method to take a source array (of objects that are all out of order) and a reference array (that has objects in a desired (and totally arbitrary) order), and returns an array where the items of the source array have been reorganized to match the reference array.
- (NSArray *) reorderArray:(NSArray *)sourceArray toArray:(NSArray *)referenceArray
{
NSMutableArray *returnArray = [[NSMutableArray alloc] init];
for (int i = 0; i < [referenceArray count]; i++)
{
if ([sourceArray containsObject:[referenceArray objectAtIndex:i]])
{
[returnArray addObject:[arrReference objectAtIndex:i]];
}
}
return [returnArray copy];
}
Note that this is very fragile. It uses NSArray
's containsObject:
method, which ultimately will call NSObject
's isEqual:
. Basically, it should work great for arrays of NSString
s, NSNumber
s, and maybe NSDate
s (haven't tried that one yet), but outside of that, YMMV. I imagine if you tried to pass arrays of UITableViewCell
s or some other really complex object, it would totally sh*t itself, and either crash or return total garbage. Likewise if you were to do something like pass an array of NSDate
s as the reference array and an array of NSString
s as the source array. Also, if the source array contains items not covered in the reference array, they'll just get discarded. One could address some of these issues by adding a little extra code.
All that said, if you're trying to do something simple, it should work nicely. In your case, you just send arrayOne
from the answer you posted as the source array, and arrayTwo
as the reference array.
Upvotes: 0
Reputation: 3803
As everyone said, I can't order my keys as they appear in my NSDictionary log because a NSDictionary is not ordered.
I asked people from the API to return an array instead:
0 => name : key 1
value : value 1
1 => name : key 2
value : value 2
/----------------------------------------------------------------------------/
Too bad there isn't a method "sortedArrayUsingArray" used like that :
NSArray * arrayOne = [@"key E", @"key A", @"key C"];
NSArray * arrayTwo = [@"key A", @"key B", @"key C", @"key D", @"key E", @"key F"];
NSArray * orderedArray = [arrayOne sortedArrayUsingArray: arrayTwo];
Upvotes: 1