Inserting NSDictionary into sorted NSMutableArray - objective-c

I want to insert an NSDictionary object into an array and have the array sorted by objectForKey.
I managed to do this by inserting, re-sorting and reloading the array, which works fine, but I figured there would be a better method, which there is, I just don't know how to use it.
Current code:
-(NSMutableArray*)sortArray:(NSMutableArray*)theArray {
return [[theArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"n"
ascending:YES]]] mutableCopy];
}
returns the re-sorted array. Fine. Works perfectly, but... is it the most efficient?
From another question I gather that this is the method to use to find the index to insert into:
NSUInteger newIndex = [array indexOfObject:newObject
inSortedRange:(NSRange){0, [array count]}
options:NSBinarySearchingInsertionIndex
usingComparator:comparator];
[array insertObject:newObject atIndex:newIndex];
The problem is I have no idea how to use the comparator method, and if that's even possible when I want to sort by objectForKey for each index.
Can anyone exemplify the above method when the key of the object (newObject in above example) to sort by is, let's say:
[newObject objectForKey:#"sortByThis"];

Use NSSortDescriptor
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortByThisKey" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];

here is the simple example for comparator
- (NSComparisonResult)compareResulst:(CustomObject *)otherObject {
if(self.name isEqualToString:key)
{
return NSOrderedAscending;
}
else
{
return NSOrderedDescending
}
}
NSArray *sArray;
sArray = [unsArray sortedArrayUsingSelector:#selector(compareResulst:)];
this will sort the array. it will iterate through object and based on your if else it will move object up and down ...

Here's an example of sorting
//For make a we're adding 5 random integers into array inform of NSDictionary
//here, we're taking "someKey" to store the integer (converted to string object) into dictionary
NSMutableArray *array = [NSMutableArray array];
for(int i = 1; i<=5; i++) {
[array addObject:[NSDictionary dictionaryWithObject:[#(arc4random()%10) stringValue] forKey:#"someKey"]];
}
//create a sort descriptor to sort the array
//give the key in dictionary for which you want to perform sort
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"someKey" ascending:YES];
//we're doing self sort for mutable array, & that's it, you'll have a sorted array.
[array sortUsingDescriptors:#[sort]];
N.B.
1.Instead of "someKey" from above example you can set any key for which you want to perform sort.
2.There's some other methods for sorting, you can use the one base on your requirement.
3.see #[sort] in code. Its full version is, [NSArray arrayWithObject:sort];

Related

Sorting JSON Data by date

Hi I'm getting data online from a JSON file and I'm trying to sort it by date in descending order, I've done it before using an XML parser using an RSS feed and tried to use the same concept but can't seem to get it and it crashes every time.
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSDictionary *dataDict = [dict objectForKey:#"data"];
NSArray *array = [dataDict objectForKey:#"items"];
for (int i=0; i<[array count]; i++) {
SongInfo *song = [[SongInfo alloc]init];
NSMutableDictionary *entry = [array objectAtIndex:i];
song.uploaded = [entry objectForKey:#"uploaded"];
song.uploader = [entry objectForKey:#"uploader"];
NSComparator comparator = ^(NSDictionary *a, NSDictionary *b) {
return [a[#"uploaded"] compare:b[#"uploaded"]];
};
NSUInteger index = [songsArray indexOfObject:entry
inSortedRange:NSMakeRange(0, [songsArray count])
options:NSBinarySearchingInsertionIndex
usingComparator:comparator];
[songsArray insertObject:song atIndex:index];
EDIT: Managed to fix it by using the NSSortDescriptor and putting it into an array and then back into the same array, not sure if there is a better way to do this but this is how I did it...
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"uploaded"
ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [songsArray sortedArrayUsingDescriptors:sortDescriptors];
songsArray = [NSMutableArray arrayWithArray:sortedArray];
// [songsArray addObject:[song copy] atIndex:index];
[songsArray addObject:song];
You're comparing objects inserted in the songsArray with a comparator that takes in two dictionaries. It seems like the comparator should compare SongInfo objects rather than NSDictionaries.
We can't see what songsArray is. Creating a sorted array manually like you do is really inefficient. Call the NSArray method sortedArrayUsingComparator instead, and there is no need to create SongInfo objects.
On the other hand, if an array of SongInfo* is what you want, create that array first as an NSMutableArray with all the SongInfo's from the JSON data, then sort that array by calling sortUsingComparator.
Note that in the comparator block you can actually use the type of the object: So in the first case NSDictionary* instead of id, in the second case SongInfo* instead of id.

Objective-C NSMutableArray: Organize array of photos by date key

I have an array of dictionaries..looks like this.
(
{name = somename;
date = NSDate;
other_params = some other params;
},
...
)
How can I then sort the array items by NSDate (oldest to newest or vice versa). Do I just do a basic select-sort algorithm or is there a shorter way?
You can sort the array using descriptors or using comparators, whatever you feel more comfortable with. Here is an example of using comparators:
NSArray *sortedArray = [myArray sortedArrayUsingComparator: ^(id obj1, id obj2) {
return [[obj1 date] compare:[obj2 date]];
}];
Here's the sort descriptors option:
// Adjust the 'ascending' option to invert the sort order.
NSSortDescriptor *dateSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES];
// The sort descriptors have to go into an array.
NSArray *sortDescriptors = [NSArray arrayWithObject:dateSortDescriptor];
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
You can also sort in place if you're using an NSMutableArray and don't need to keep its original order.

Sort an NSArray with NSDictionary

I'm using NSSortDiscriptors to sort an NSArray.
Every index in the array contains a dictionary with key,value entries. This dictionary also holds another dictionary.
My problem that I want solve is to sort the array based on values on the first dictionary, but also on some values in the dictionary it contains.
The following is the sort method I use for the other values in the array.
- (void)sortArray {
if ([array count] != 0) {
// Reports sortingDescriptors
NSSortDescriptor * city = [[NSSortDescriptor alloc] initWithKey:#"City" ascending:YES];
NSSortDescriptor * name = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:YES];
NSSortDescriptor * country = [[NSSortDescriptor alloc] initWithKey:#"Country" ascending:YES];
[reportsArray sortUsingDescriptors:[NSArray arrayWithObjects:city, name, country, nil]];
[name release];
[city release];
[country release];
}
}
The array looks like this:
[{name = "";
city = "";
country = "";
date = {
dateAdded = "";
dateRemoved = "";
}
}];
So I also want to sort on, if have value on dateAdded for example.
You can specify a key path when you create the NSSortDescriptor, this way you can sort the NSArray with a NSDictionary.
You might want to check if the dictionary contains a value like that :
// you can't set nil as a value for a key
if([yourDictionary objectForKey:#"yourKey"] == [NSNull null]) { ... }
Then you need to sort remaining objects but the dictionary, to do so, make a copy of your array without the dictionary entry by doing something like :
NSMutableArray *tmpArray = [NSMutableArray arrayWithArray:firstArray];
[tmpArray removeObjectAtIndex:theIndexOfTheDictionary];
// sort your array, don't forget to catch the returned value
NSMutableArray *sortedArray = [tmpArray sortUsingDescriptors:[NSArray arrayWithObjects:city, name, country, nil]];
// finally, put the dictionary back in (if needed)
[sortedArray insertObject:theDictionary atIndex:theIndexYouWant];
Are you saying that the objects in the array have a City, Name and Country property but also a dictionary property and you want to sort on one of the keys in the dictionary? Or are you saying that the entries in the array are dictionaries but sometimes the City, Name or Country key is missing? Or are you saying that some of the entries are dictionaries and some are objects with the listed properties?
In any case, you can get more flexibility by creating a sort descriptor using initWithKey:ascending:comparator:. This allows you to supply a comparator block as the sort function which is more flexible than a straight selector e.g.
NSComparator mySort = ^(id obj1, id obj2)
{
NSComparisonResult ret = NSOrderedSame;
if ([obj1 isKindOfClass: [NSDictionary class]] && ![obj2 isKindOfClass: NSDictionary class]])
{
ret = NSOrderedAscending;
}
else if (![obj1 isKindOfClass: [NSDictionary class]] && [obj2 isKindOfClass: NSDictionary class]])
{
ret = NSOrderedDescending;
}
return ret;
};
NSSortDescriptor* descriptor = [[NSSortDescriptor alloc] initWithKey: #"self" ascending: YES comparator: mySort];
will give you a sort descriptor that sorts the array putting all the NSDictionaries first and other objects afterwards. (self is a key possessed by all NSObjects that returns the object itself).
NSArray *unsortedArray=[NSArray arrayWithObjects:[NSDictionary dictionaryWithObjectsAndKeys:#"anil",#"personInDictionary.lastName" ,nil],[NSDictionary dictionaryWithObjectsAndKeys:#"aneelu",#"personInDictionary.lastName", nil] ,[NSDictionary dictionaryWithObjectsAndKeys:#"kumar",#"anil.lastName", nil] ,nil];
NSSortDescriptor * descriptor = [[[NSSortDescriptor alloc] initWithKey:#"personInDictionary.lastName" ascending:YES] autorelease]; // 1
NSArray * sortedArray = [unsortedArray sortedArrayUsingDescriptors:
[NSArray arrayWithObject:descriptor]];
NSLog(#"sortedArray values %#",sortedArray);
for (id object in [sortedArray valueForKey:#"personInDictionary.lastName"]) {
NSLog(#"sortedArray value %#",object);
}

How to sort an array which contains Dictionaries?

I have an array which contains dictionaries in it; so how can I sort the array according to dictionary key values?
If every element in the array is a dictionary containing a certain key, you can sort the array using a sort descriptor. For instance, if every element is a dictionary containing a key called "name":
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:#"name"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
NSArray *sortedArray = [array sortedArrayUsingDescriptors:sortDescriptors];
The other way to achieve this would be using sortedArrayUsingComparator: method
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [[obj1 valueForKey:#"value"] compare:[obj2 valueForKey:#"value"]];
}];
why don't you use a sorted dictionary where the property of sorted elements comes already with the data structure?
Please do check it out here
Hope this helps.
The above shared answer by Bavarious helped me.Just want to add one more thing.If you want to sort a mutable array use something like the below code
NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortByName];
NSMutableArray *sortedArray = [[NSMutableArray sortedArrayUsingDescriptors:sortDescriptors]mutableCopy];
let arrDescriptor = NSSortDescriptor(key: "order", ascending: true)
let sortDescriptors: NSArray = [arrDescriptor]
let sortedArray = instancesubArray.sortedArray(using: sortDescriptors as [AnyObject] as [AnyObject] as! [NSSortDescriptor])
print(sortedArray)

Sorting NSDictionary

I was wondering if someone can show me how to sort an NSDictionary; I want to read it starting from the last entry, since the key is Date + Time and I want to be able to append it to an NSMutableString. I was able to read it using an enumerator but I don't get the results I want.
Thanks
For your requirements the easiest way is to create a new array from the keys, sort that, then use the array to reference items from the original dictionary.
(Note myComparison is your own method that will compare two keys).
NSMutableArray* tempArray = [NSMutableArray arrayWithArray:[myDict allKeys]];
[tempArray sortedArrayUsingSelector:#selector(myComparison:)];
for (Foo* f in tempArray)
{
Value* val = [myDict objectForKey:f];
}
I've aggregated some of the other suggestions on StackOverflow on sorting an NSDictionary into something very compact that will sort alphabetically. I have a Plist file in 'path' that I load in to memory and want to dump.
NSDictionary *glossary = [NSDictionary dictionaryWithContentsOfFile: path];
NSArray *array1 = [[glossary allKeys] sortedArrayUsingDescriptors:#[ [NSSortDescriptor sortDescriptorWithKey:#"" ascending:YES selector:#selector(localizedStandardCompare:)] ]];
for ( int i=0; i<array1.count; i++)
{
NSString* key = [array1 objectAtIndex:i];
NSString* value = [glossary objectForKey:key];
NSLog(#"Key=%#, Value=%#", key, value );
}