So I have this NSDictionary like so:
NSDictionary *productionSchedule = [[[NSMutableDictionary alloc]initWithDictionary:[[areaData GetProductionScheduleData:communityDesc] objectForKey:#"Root"]] autorelease];
The data for the NSDictionary is coming from an API and due to the fact that NSDictionary does not do ordering, the order of the data in API is different in the NSDictionary, so now I am trying to put the keys of the NSDictionary into an NSMutableArray to handle the ordering. In my NSDictionary I have a value called SortOrder and I am trying to put the data in NSDictionary into NSMutableArray based on this value SortOrder (I have about 389 items and the SortOrder goes from 0 - 389) How would I do this?
I have this screenshot that will show you what my data is like:
What I am trying to do is put the key 'V3C0183' but as the 82nd item (there will be 81 items before this)
I am assuming I will have to do a foreach loop like so:
NSMutableArray *prodSchedSortedKeys
for(int i = 0;i<[productionSchedule count];i++)
{
[prodSchedSortedKeys addObject: ? ];
}
I just dont know what the next step would be to add an object based off the sort order....please help.
NSDictionary *dic = //your dictionary;
NSArray<NSDictionary *> *values = dic.allValues;
[values sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1[#"SortOrder"] integerValue] > [obj2[#"SortOrder"] integerValue];
}];
Now the dic is ordered.
But this is not the best solution of this problem. Server's data should be ordered instead, that the key like "VC31083" should in the key-value pairs too.
Edit1: sortedArrayUsingComparator: is used for normal sort of array, the performance isn't very well if the content is too large. Especially in this compare, it do addition actions: get value from dictionary, transform NSString to int, and then compare. You can Log to see how much time it spend on this sort with your data.
NSMutableDictionary/NSDictionary can't do that. Take a look at e.g. Matt Gallaghers OrderedDictionary.
Also take a look at this answer:
Getting NSDictionary keys sorted by their respective values
Related
I have an NSArray and I need to get data from two keys and put together in a NSMutableDictionary. One key has stringvalues and the other NSNumbervalues. When I try to create NSCountedSetwithout adding the keys I want to use to separate arrays, it doesn't work, because the objects are not identical, basically, I need to check if objectId is identical, don't matter if the other keys are different.
Here is the initial code:
for (PFObject *objeto in objects) {
PFObject *exercicio = objeto[#"exercicio"];
NSString *string = exercicio.objectId;
NSNumber *nota = objeto[#"nota"];
[exercicios addObject:string];
[notas addObject:nota];
So I create two NSMutableArraysand store the values I need. When I logthe arrays after this, they are perfectly ordered, meaning the NSStringis in the same indexof the NSNumberit belongs to in the other array. So far, so good.
Now, when I create the NSCountedSetwith the strings, it changes the order.
NSCountedSet *countedExercicios = [[NSCountedSet alloc] initWithArray:exercicios];.
My goal is to sum the NSNumbers pertaining to an specific object, therefore, when the order changes, I lose the connection between the two arrays.
I'm not sure what I could do to solve this problem, or even if there's a different approach to achieve the result I need.
You can create NSDictionary and add it to array. You will have just one array and you won't lose the connection, you can use objectId as a key and NSNumber as a value:
for (PFObject *objeto in objects) {
PFObject *exercicio = objeto[#"exercicio"];
NSString *string = exercicio.objectId;
NSNumber *nota = objeto[#"nota"];
NSDictionary *dict = #{string: nota};
[newArray addObject: dict];
}
When you need get all key (objectId) you can use NSPredictate.
Hope this help
I would like some help sorting an NSArray of NSDictionary values based on each objects ISV key.
This is the code I have so far for creating my array objects so you have a better idea of what I am trying to do.
NSArray *combinedKeysArray = [NSArray arrayWithObjects:#"HASM", #"ISL", #"ISV", nil];
valuesCombinedMutableArray = [NSMutableArray arrayWithObjects:[dict objectForKey:#"HASM"],
[dict objectForKey:#"ISL"],
[dict objectForKey:#"ISV"],
nil];
combinedDictionary = [NSDictionary dictionaryWithObjects:valuesCombinedMutableArray
forKeys:combinedKeysArray];
[unSortedrray addObject:combinedDictionary];
// how do I then sort unSortedArray by the string values in each object ISV key?
any help would be greatly appreciated.
This can solve your problem
How to sort an NSMutableArray with custom objects in it?
https://stackoverflow.com/a/805589/1294448
You can use NSSortDescriptor to sort NSArays
Then in NSArray you have a method called sortedArrayUsingDescriptors
Or NSComparisonResult ca also be helpful some time http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html#//apple_ref/doc/uid/20000138-BABCEEJD
you won't be able to sort unSortedArray because it will only have one element in it (ie in your last line of code you are adding a single object by addObject).
That said, you cannot sort the dictionary either.. b/c dictionaries are unsorted by definition.
you can iterate over the keys of the dictionary in a specific order though, you can sort an array containing the keys of the dictionary.
NSArray *keys = [theDictionary allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingSelector:#selector(compareMethod:)];
You can use -sortedArrayUsingComparator: to sort any way you need.
[unSortedrray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *dict1, NSDictionary *dict2) {
return [[dict1 objectForKey:#"ISV"] localizedCompare:[dict2 objectForKey:#"ISV"]];
}];
I'm communicating with an API that sends back an NSDictionary as a response with data my app needs (the data is basically a feed). This data is sorted by newest to oldest, with the newest items at the front of the NSDictionary.
When I fast enumerate through them with for (NSString *key in articles) { ... } the order is seemingly random, and thus the order I operate on them isn't in order from newest to oldest, like I want it to be, but completely random instead.
I've read up, and when using fast enumeration with NSDictionary it is not guaranteed to iterate in order through the array.
However, I need it to. How do I make it iterate through the NSDictionary in the order that NSDictionary is in?
One way could be to get all keys in a mutable array:
NSMutableArray *allKeys = [[dictionary allKeys] mutableCopy];
And then sort the array to your needs:
[allKeys sortUsingComparator: ....,]; //or another sorting method
You can then iterate over the array (using fast enumeration here keeps the order, I think), and get the dictionary values for the current key:
for (NSString *key in allKeys) {
id object = [dictionary objectForKey: key];
//do your thing with the object
}
Dictionaries are, by definition, unordered. If you want to apply an order to the keys, you need to sort the keys.
NSArray *keys = [articles allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingSelector:#selector(compare:)];
for (NSString *key in sortedKeys) {
// process key
}
Update the way the keys are sorted to suit your needs.
As other people said, you cannot garantee order in NSDictionary. And sometimes ordering the allKeys property it's not what you really want. If what you really want is enumerate your dict by the order your keys were inserted in your dict, you can create a new NSMutableArray property/variable to store your keys, so they will preserve its order.
Everytime you will insert a new key in the dict, insert it to in your array:
[articles addObject:someArticle forKey:#"article1"];
[self.keys addObject:#"article1"];
To enumerate them in order, just do:
for (NSString *key in self.keys) {
id object = articles[key];
}
I have an NSMutableDictionary of websites
[dictionaryOfSites setObject:#"http://www.example.com" forKey:#"Example.com"];
[dictionaryOfSites setObject:#"http://www.site1.com" forKey:#"Site1"];
[dictionaryOfSites setObject:#"http://www.apple.com" forKey:#"Apple"];
I know you can't sort a dictionary. But I've read that other people have used an NSMutableArray as the key and the array can be sorted.
So if I setup a new array
[[arrayKey alloc] initWithObjects:#"Example.com", #"Site1", #"Apple", nil];
I would then modify my first snippet to
[dictionaryOfSites setObject:#"http://www.example.com" forKey:[arrayForKey objectAtIndex:0]];
[dictionaryOfSites setObject:#"http://www.site1.com" forKey:[arrayForKey objectAtIndex:1]];
[dictionaryOfSites setObject:#"http://www.apple.com" forKey:[arrayForKey objectAtIndex:2]];
In this simple problem, I had 3 sites so I "hard" coded it. How would I do the same thing if my list of sites was 100? How would the order of the sites be maintained?
If I sort my array
[arrayKey sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
Wouldn't index 2 become index 0? If it becomes index 0 then you can see the dictionaryOfSites has the wrong label with the URL.
So you can use a custom class (as I mentioned above in my comment), or better yet use an NSDictionary to store the values as MarkM suggested.
EDIT: "i don't have to maintain a dictionary. its a new app from the ground up."
Since you don't need to start with one big dictionary like you posted, it would be better to just store individual dictionary objects for each site in an array and not have to worry about the conversion.
// Setup the initial array
NSMutableArray *arrayOfSites = [NSMutableArray new];
[arrayOfSites addObject:#{#"Name" : #"Example.com",
#"URL" : #"http://www.example.com"}];
[arrayOfSites addObject:#{#"Name" : #"Site1",
#"URL" : #"http://www.site1.com"}];
[arrayOfSites addObject:#{#"Name" : #"Apple",
#"URL" : #"http://www.apple.com"}];
// At this point, arrayOfSites contains a dictionary object for each site.
// Each dictionary contains two keys: Name and URL with the appropriate objects.
// Now we just need to sort the array by the Name key in the dictionaries:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
[arrayOfSites sortUsingDescriptors:[NSArray arrayWithObjects:descriptor, nil]];
NSLog(#"%#", arrayOfSites);
Results:
2013-05-07 18:19:08.386 Testing App[75712:11f03] (
{
Name = Apple;
URL = "http://www.apple.com";
},
{
Name = "Example.com";
URL = "http://www.example.com";
},
{
Name = Site1;
URL = "http://www.site1.com";
} )
To access the data, you would use:
NSString *name = [[arrayOfSites objectAtIndex:indexPath.row] objectForKey:#"Name"];
Note that arrayOfSites should be a declared property of your class so that you can access it from different methods.
What you need to do is store your NSDictionary objects in the array and then access a value from that array to do the sorting if you wish. You don't actually store a new string for the sorting. You just check the value of a certain key in the dictionary at the index in the array.
Here is a good source for sorting an array of dictionaries
I have a problem which I can't solve for a long time. I have a JSON response from the server which is parsed to NSDictionary lastMsgs as in the image below:
So for example 1323 it's a key and it associated with NSDictionary (which contains keys such as body, subject etc and values). So the problem I need in some way delete an entry which nested NSDictionary value has entry : type = 1. I don't know how to do this. I tried to do this:
NSMutableArray* _ModelVals = [[lastMsgs allValues] mutableCopy];
for (int i =0; i<[_ModelVals count]; i++) {
string_compare = [NSString stringWithFormat:#"%#" , [_ModelVals objectAtIndex:i]];
if ([string_compare rangeOfString:#"type = 1"].location != NSNotFound) {
[_ModelVals removeObjectAtIndex:i];
}
}
But it is work not correctly and delete not all entries which has type = 1. So the question - how can I implement this and delete entry in nested NSDictionary?
There is no value "type = 1" in the dictionary. That's just the log. You get the value of a key in a dictionary using [dict objectForKey:#"key"] or dict[#"key"].
Judging from your log, the type seems to be an NSNumber, not an NSString. Just get the int representation of it (assuming the type is an integer) and use a simple C int to int comparison.
And you can't filter an array like that. You will skip an entry. If you remove an entry, you have to decrease i by 1.
Or use this simpler solution:
NSSet *keys = [lastMsgs keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
return [obj[#"type"] intValue] == 1;
}];
NSMutableDictionary *dict = [lastMsgs mutableCopy];
[dict removeObjectsForKeys:[keys allObjects]];
This will first collect the keys of all objects (dictionaries) that have a type of 1 and then remove those from a mutable copy of the original dictionary.
You cannot add or remove objects from a collection while enumerating though it. I would create a another array that you can store references to the objects that you want to delete and remove them after you have looped though it.