Reorganize dictionary order by values? - ios

I have an app that receives an Json file from my webserver and I convert to NSDictionary as you can see below:
[NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]
The structure of my dictionary is as follows:
[0] => { "name" = "josh", meters = "8" }
[1] => { "name" = "lina", meters = "10" }
[2] => { "name" = "pall", meters = "21" }
You can see that data is already organized by the key meters, unfortunately my webserver not give the possibility to maintain an open connection, in this case, the new records will come through the APNS (push notification)
Assuming that comes the following record by notification:
{"name" = "oli", meters = "12"}
I insert it in my dictionary, but once that's done, how can I rearrange my array and order by meters?

There's no order inherent in the dictionary. That you see an ordering in the initial set is accidental.
Arrays have ordering, and you can get an array from a dictionary by sending it allKeys or allValues.
Using this fact to organize the dictionary, you might try something like this:
NSArray *orderedPairs = [#[] mutableCopy];
for (id key in [someDictionary allKeys]) {
[orderedPairs addObject:#[key, someDictionary[key]]];
}
[orderedPairs sortUsingComparator:^NSComparisonResult(NSArray *a, NSArray *b) {
// return [a[0] compare:b[0]]; // to sort by key
return [a[1] compare:b[1]]; // to sort by value
}];
Note that this will result in an array -- not a dictionary -- but one that is ordered.

Dictionary doesn't have order. it's simply key-value pair. you can fetch value for particular key so doesn't require sorting or ordering like array.

Related

Sort NSDictionary keys according to NSArray elements

I have NSDictionary filled with many objects. I have sorted the keys in a desired pattern and now I have the keys only in a new NSArray. How to apply the changes so the order of the elements in the array to be reflected in the dictionary?
For ex. NSArray -> ["D" , "B" , "A" , "C"] this order I want to apply to the keys in the dictionary.
NSDictionary -> {{"A" : <something>} , {"B" : <something>} , {"C" : <something>} , {"D" : <something>}}
You don't. You iterate over the keys in the array and then pull out the data from the dictionary.
for (NSString *key in sortedKeys) {
id value = dictionary[key];
// do something...
}
If you need ordering you might consider using NSOrderedSet or rolling your own data structure to do this. For example, I have created data structures that use both NSIndexSet and NSDictionary to provide key/value storage with faster sorted enumeration.

Dictionary key-value using with array

I have an array and it has lots of dictionary's keys it comes from API. My array as follows
Dictionary keys array :
NSArray *arr = #[#"01", #"02", #"03"];
Dictionary with key-value pairs
NSDictionary *dic = #{#"01": #"Hero", #"02" : #"Enemy", #"03" : #"Boss"};
Basically i want to match array values corresponding to dictonary keys without using array. I found a solition about that but I don't want to use for-loop for every cell(I have a lots of cell). My solution is like that
for(NSString *item in arr) {
[convertedArr addObject:[dic valueForKey:item]];
}
NSLog(#"%#", [convertedArr componentsJoinedByString:#","]);
Asumme have an array like this (1,2,3) and dictionary looks like {1 = "a", 2 = "b", 3 = "c"} I just want to give an array and it should return dictionary values like this ("a","b","c")
Anybody should give me better approach without using array? Thanks.
You can replace your for-loop by
NSArray *convertedArr = [dic objectsForKeys:arr notFoundMarker:#""];
which is at least less code. (The notFoundMarker: is added for all keys
in the array which are not present in the dictionary. Your code would crash
in that situation.)
It might perform slightly better because it is a library
function. But I doubt that the difference is big, because in any case a dictionary
loopup is required for all keys in arr.

RestKit post with NSArray of NSDictionary numbering

I am using RestKit to Post an object to the server.
The object contains an NSArray, which I convert to NSDictionaries before adding it to the parameters list (an NSDictionary)
the NSDictionary queryParams looks like this (printed out using NSLog, and removing some fields for clarity)
requestParams = {
"app_version" = "v1.0(1.006)";
"extended_information" = {
"travel_locations" = (
{
"Aircard_or_Tablet" = 0;
Country = "United States";
"End_Date" = "04/12/2013";
"Start_Date" = "03/12/2013";
}
);
"using_voice" = 0;
};
}
I then send it:
[objectManager postObject:nil path:server_path parameters:requestParams success:… failure:…]
The problem is that when RestKit creates the query string, it seems to increment the counter for each key in the dictionary, rather than per item in the array. The following is what is received by the server. I added a line break after each parameter for clarity:
app_version=v1.0(1.006)
&extended_information[travel_locations][0][Aircard_or_Tablet]=0
&extended_information[travel_locations][1][Country]=United States
&extended_information[travel_locations][2][End_Date]=04/12/2013
&extended_information[travel_locations][3][Start_Date]=03/12/2013
&extended_information[using_data]=0
The server is expecting (and I would expect) travel_locations to remain at [0] for all the keys in that one object, like this:
app_version=v1.0(1.006)
&extended_information[travel_locations][0][Aircard_or_Tablet]=0
&extended_information[travel_locations][0][Country]=United States
&extended_information[travel_locations][0][End_Date]=04/12/2013
&extended_information[travel_locations][0][Start_Date]=03/12/2013
&extended_information[using_data]=0
And, of course, if a second travel_location were there it would have [1], the third would have [2], and so forth.
Is this a bug in RestKit? Is there a better way I can be sending this request so that it does work? I do not have the option of changing the server.
To question is:
How can I have RestKit convert the NSDictionary for parameters properly so that it does not increment the array index identifier for each key in the array object?
Thanks,
-Nico

Sort array based on second array order

I have an array from a plist and each value contains an key and a string and a secondary array that I get from a json file online. I want to order the secondary array based on the keys in the first array.
I want to achieve something like this:
array1:
Item0 - EUR
- String
Item1 - USD
- String
Item2 - AUD
- String
etc
array2:
Item0 - AUD
- 123.242
Item1 - EUR
- 535.123
Item2 - USD
- 325.646
etc
I have the same key index on both but I want to get the value for the key index from array2 based on the order of the key index in array1.
I have researched online but I cannot find a suitable solution that I can understand how to implement it.
How can I implement this?
Here is the plist file - https://gist.github.com/iulianvarzaru/11c400ba1edf4a165082
And the json file - https://gist.github.com/iulianvarzaru/1915e02a9201c57f49b3
Given that the JSON file you've linked to doesn't contain an array but a dictionary, you can simply iterate over array1 from the plist file. Each element of that array is a dictionary with a "Cod" key and a "Descriere" key. Get the value for the "Cod" key and then simply use that value as the key into the dictionary from the JSON file.
NSDictionary* jsonFileDict = ...;
NSDictionary* jsonFileInnerDict = jsonFileDict[#"rate"];
for (NSDictionary* dict in array1)
{
NSString* code = dict[#"Cod"];
NSNumber* jsonNumber = jsonFileInnerDict[code];
// Do something with jsonNumber
}
It sounds like these are key-value pairs, in which case, you can convert it to a Map, and then do direct lookups.
If you can manipulate the JSON file as JSON, then it reduces a conversion, but may not be the most efficient implementation.
Caveats:
This method assumes that you wont have key overloading (which is possible in a numeric array, but not in a map)
This requires a conversion from one data structure to another
EDIT: (due to increased information by OP).
The JSON file you receive doesn't contain an array, it contains an object. Thus, all the values are direct-lookup. So, you can traverse your array in Obj-c, and directly access the corresponding values in the JSON.
Sorry about the lack of actual code-samples.
You are dealing with a dictionary in the response, not an array.
You should transform it to something like
{
#"currency": #"EUR",
#"value": 123.45
}
create and sort it it like
NSArray *keys = #[#"EUR",#"USD",#"AUD"];
NSDictionary *dict = #{#"AUD":#(123.242), #"EUR": #(535.123), #"USD": #(325.646)};
NSMutableArray *result = [#[] mutableCopy];
for (NSString *key in keys) {
[result addObject:#{#"value":dict[key], #"currency": key}];
}
NSLog(#"%#", result);
(
{
currency = EUR;
value = "535.123";
},
{
currency = USD;
value = "325.646";
},
{
currency = AUD;
value = "123.242";
}
)
Or write a model class that can handle this information.

iOS sort one array based on order of strings in another array

This is another very specific problem I am trying to solve.
I am pulling a list a twitter user accounts logged into the users settings application. This returns an array with the usernames in the correct order.
I then pass this array to this twitter API:
https://api.twitter.com/1.1/users/lookup.json
The returned array contain all the additional data I need for each user account logged in. The first array contains NSStrings (usernames), the returned array has been parsed to contain dictionaries that have a key and value for the username, name, and profile pic.
Problem now is that the order is completely different than the first array I passed.. This is expected behavior from Twitter, but it needs to be in the exact same order (I will be referencing the original index of the AccountStore which will match the first array, but not the new array of dictionaries).
How can I tell the new array to match the contained dictionaries to be the same order as the first array based on the username key?
I know this sounds confusing, so let me at least post the data to help.
Here is the first array output:
(
kbegeman,
indeedyes,
soiownabusiness,
iphonedev4me
)
Here is what the second array outputs:
(
{
image = "https://si0.twimg.com/profile_images/3518542448/3d2862eee546894a6b0600713a8de862_normal.jpeg";
name = "Kyle Begeman";
"screen_name" = kbegeman;
},
{
image = "https://si0.twimg.com/profile_images/481537542/image_normal.jpg";
name = "Jane Doe";
"screen_name" = iPhoneDev4Me;
},
{
image = "https://twimg0-a.akamaihd.net/profile_images/378800000139973355/787498ff5a80a5f45e234b79005f56b5_normal.jpeg";
name = "John Doe";
"screen_name" = indeedyes;
},
{
image = "https://si0.twimg.com/sticky/default_profile_images/default_profile_5_normal.png";
name = "Brad Pitt";
"screen_name" = soiownabusiness;
}
)
Due to the way Twitter returns the data, it is never the EXACT same order, so I have to check this every time I call these methods.
Any help would be great, would save my night. Thanks in advance!
You want the array of dictionaries be sorted by comparing screen_name value with your first array. Right? Also, the screen name may have different case than your username. Right?
I would use mapping dictionary:
Create dictionary from screen name to user dictionary:
NSArray *screenNames = [arrayOfUserDicts valueForKeyPath:#"screen_name.lowercaseString"];
NSDictionary *userDictsByScreenName = [NSDictionary dictionaryWithObjects:arrayOfUserDicts forKeys:screenNames];
Build final array by finding user dictionary for usernames in your array:
NSMutableArray *sortedUserDicts = [NSMutableArray arrayWithCapacity:arrayOfUsernames.count];
for (NSString *username in arrayOfUsernames) {
NSDictionary *userDict = [userDictsByScreenName objectForKey:username.lowercaseString];
[sortedUserDicts addObject:userDict];
}
First generate a mapping that maps the "screen_name" to the corresponding dictionary
in the second array:
NSDictionary *map = [NSDictionary dictionaryWithObjects:secondArray
forKeys:[secondArray valueForKey:#"screen_name"]];
Then you can create the sorted array with a single loop:
NSMutableArray *sorted = [NSMutableArray array];
for (NSString *name in firstArray) {
[sorted addObject:map[name]];
}
That sort order isn't something that could be easily replicated (i.e. it's not alpha, etc). Instead, you should just use that original NSArray as a guide to match data from the NSDictionary from Twitter. For example:
[twitterDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSInteger index = [yourLocalArray indexOfObject:obj];
if (index != NSNotFound) {
// You have a match, do something.
}
}];
lets name your arrays as firstArray and secondArray.
NSArray *sortedArray = [secondArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [#([firstArray indexOfObject:[obj1 objectForKey:#"name"]]) compare:#([firstArray indexOfObject:[obj2 objectForKey:#"name"]])];
}];

Resources