Swissdude
Swissdude

Reputation: 3556

iOS - Convert a JSON object to an ordered array

I have a JSON file with key/value-pairs for a list of countries and their country-codes. I'm reading it with Objective-C and want to present it in a UIPicker. Problem is, when I store the JSON data into a NSDictionary, the original order is lost and the order of the UIPicker elements is pretty arbitrary (I know, dictionaries don't have a particular order).

What's the easiest way to preserve to original order? Do I have to create two files, one with the country-codes and one with the country names in the same order and read both into an array? - I really wanna avoid that...

[Edit]

As per request, an excerpt of the JSON-Data (stored in a local file)

{"af":"Afghanistan",
    "al":"Albania",
    "dz":"Algeria",
    "as":"American Samoa",
    "ad":"Andorra",
    "ao":"Angola",
    "ai":"Anguilla",
    "aq":"Antarctica",
    "ag":"Antigua and Barbuda",
    "ar":"Argentina",
    "am":"Armenia",
    "aw":"Aruba",
    "ac":"Ascension Island (Atlantic ocean)",
    "au":"Australia",
    "at":"Austria",
    "az":"Azerbaijan",
    "bs":"Bahamas",
    "bh":"Bahrain",
    "bd":"Bangladesh",
    "bb":"Barbados",
    "by":"Belarus",
    "be":"Belgium",
    "bz":"Belize",
    "bj":"Benin",
    "bm":"Bermuda",
    "bt":"Bhutan",
    "bo":"Bolivia",
    "ba":"Bosnia",
    "bw":"Botswana",
    "bv":"Bouvet Island (Atlantic ocean)",
    "br":"Brazil",
    ... }

[Edit 2]

I'm using this code to read the JSON data and convert it to a NSDictionary:

NSURL *jsonPath = [[NSBundle mainBundle] URLForResource:@"countries" withExtension:@"json"];
NSString *stringPath = [jsonPath absoluteString];

NSData *countriesJSON = [NSData dataWithContentsOfURL:[NSURL URLWithString:stringPath]];

NSDictionary *parsedJson = [NSJSONSerialization JSONObjectWithData:countriesJSON options:0 error:nil];

Upvotes: 0

Views: 985

Answers (3)

Droppy
Droppy

Reputation: 9721

The issue of order and dictionaries often occurs when the dictionary needs to be displayed in a tableview. The established solution to this is to keep a separate array of dictionary keys alongside the dictionary. You can re-order the array as you (or the user) likes and do a two-stage fetch of dictionary entries via the array. This allows you to keep your original JSON format and internal storage properties/instance variables.

YourClass.m:

@interface MyClass ()
@property NSMutableArray *dictOrder;
@end

@implementation MyClass

- (void)getData
{
    self.dict = // Get dictonary from JSON
    self.dictOrder = [[self.dict allKeys] mutableCopy];
    [self.dictOrder sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
}


// UITableViewDataSource example
- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Normal cell re-use stuff
    NSString *key = self.dictOrder[indexPath.row];
    NSString *country = self.dict[key];
    // Populate cell
}

@end

Upvotes: 1

skensell
skensell

Reputation: 1451

If order is important and you have access to the JSON file, then you could change your JSON to be an array like so:

[
    ["Afghanistan", "AF"],
    ["Bangladesh", "BD"]
]

Then when you deserialize it, order will be preserved because the deserialized object will be an array of arrays.

If you don't have access to your JSON file then you could create this array of arrays from your Dictionary in code.

Edit

If you want both quick lookups and an ordering then it's tough to avoid using 2 data structures. With the JSON file you've submitted, it seems you want an array:

NSArray *countriesSorted = [parsedJson.allValues sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

However, it would be better for you to switch the order of values in your json file to be country-name:country-code. Then you could do

NSArray *countryCodesSorted = [parsedJson.allKeys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
NSString *firstCountryName = parsedJson[countryCodesSorted[0]];

Upvotes: 1

Cokile Ceoi
Cokile Ceoi

Reputation: 1346

You can change your JSON data to

[
{"af":"Afghanistan"},
{"al":"Albania"},
{"dz":"Algeria"},
{"as":"American Samoa"},
{"ad":"Andorra"},
{"ao":"Angola"},
{"ai":"Anguilla"},
...
]

Then use the code like:

NSURL *jsonPath = [[NSBundle mainBundle] URLForResource:@"sample" withExtension:@"json"];
NSData *countriesJSON = [NSData dataWithContentsOfURL:jsonPath];
NSMutableArray *countryArray = [NSJSONSerialization JSONObjectWithData: countriesJSON options:NSJSONReadingMutableContainers error:nil];

The JSON is converted to a ordered array called countryArray. the elements of the countryArray is a NSDictionary instance.

Upvotes: 3

Related Questions