So I have an array of custom "Element" objects (hey hold atomic number, chemical symbol, atomic mass, etc...) and I am having trouble sorting them by one of their properties;
Here is the code:
switch (sortDescriptor) {
case 0: {
//Sort the array by "ATOMIC NUMBER"
NSArray *sortedArray = [self.elementsArray sortedArrayUsingComparator:^(id a, id b) {
NSNumber *first = #([(SAMElement *)a atomicNumber]);
NSNumber *second = #([(SAMElement *)b atomicNumber]);
return [first compare:second];
}];
self.elementsArray = [sortedArray mutableCopy];
}
case 1: {
//Sort the array by "ELEMENT NAME"
NSArray *sortedArray = [self.elementsArray sortedArrayUsingComparator:^(id a, id b) {
NSString *first = [(SAMElement *)a elementName];
NSString *second = [(SAMElement *)b elementName];
return [first compare:second];
}];
self.elementsArray = [sortedArray mutableCopy];
}
case 2:{
NSLog(#"sorting by chemical symbol");
//Sort the array by "CHEMICAL SYMBOL"
NSArray *sortedArray = [self.elementsArray sortedArrayUsingComparator:^(id a, id b) {
NSString *first = [(SAMElement *)a chemichalSymbol];
NSString *second = [(SAMElement *)b chemichalSymbol];
return [first compare:second];
}];
self.elementsArray = [sortedArray mutableCopy];
}
case 3: {
//Sort the array by "ATOMIC MASS"
NSArray *sortedArray = [self.elementsArray sortedArrayUsingComparator:^(id a, id b) {
NSNumber *first = [(SAMElement *)a atomicMass];
NSNumber *second = [(SAMElement *)b atomicMass];
return [first compare:second];
}];
self.elementsArray = [sortedArray mutableCopy];
}
default:
break;
}
When is sorts it returns a totally random list of elements. Am i doing something wrong?
The best way to sort an array of objects by some property of the object, its using NSSortDescriptor. In initWithKey, you can set the name of the property that you want to sort.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"atomicNumber" ascending:NO];
[self.elementsArray sortUsingDescriptors:#[sortDescriptor]];
In your case, just copy this code above in each case section of your switch statement, changing the key for #"elementName" and #"chemichalSymbol".
You can change the ascending value from NO to YES, depending what type of order do you want.
Please, let me know if worked or not.
I'm not seeing the bug immediately, but you're reinventing the wheel here. The correct tool for this is sortedArrayUsingDescriptors:
[self.elementsArray sortedArrayUsingDescriptors:#[
[NSSortDescriptor alloc] initWithKey:#"atomicNumber"] ascending:YES]
]];
Try that and see if it gets rid of your bug. If you're getting random orders, that usually suggests that your comparitor is inconsistent (sometimes A>B and sometimes B>A for the same A&B).
Related
I have the following block:
sortedNameArray = [nameArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [(NSString *)obj1 compare:(NSString *)obj2 options:NSNumericSearch];
}];
That I use to take an array of Strings and alphabetize them. Now what I want to do is get it to alphabetize an array of Name objects(an object with a NSString firstName and a NSString lastName) by looking at the last name attribute then alphabetizing the objects by its lastName attribute. Here is an example of a Name object:
Name *bobSmith = [[Name alloc] init];
[bobSmith setFirstName:#"Bob"];
[bobSmith setLastName:#"Smith"]; // this is what I want to alphabetize it by
I have tried:
for (int i = 0; i < [nameArray count]; i++){
sortedNameArray = [[nameArray[i] getLastName] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [(NSString *)obj1 compare:(NSString *)obj2 options:NSNumericSearch];
}];
}
but this obviously does not work. How can I get this method to alphabetize an array of objects by looking at one of it's string attributes.... ie taking an array of Name objects, looking at their last name (an NSString) and alphabetizing the objects according to this?
sortedNameArray = [nameArray sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
return [[obj1 lastName] compare:[obj2 lastName]];
}];
You can use sortDescriptors to alphabetise an array of Name objects
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastname" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [nameArray sortedArrayUsingDescriptors:sortDescriptors];
nameArray =[NSMutableArray arrayWithArray:sortedArray];
I pulled the code from Sort Descriptor Programming Topics. Also, Key-Value Coding comes into play, in that sortedArrayUsingDescriptors: will send a valueForKey: to each element in myArray, and then use standard comparators to sort the returned values.
I have an array of objects (dictionaries) which contain a key #"Category". I have to sort it by a specific key starting by that key. For example if the values in the objects[#"Category"]: A, B ,C ,D ,E ,F ,G , H etc. and the user selects "sort by C" I need to reorder the root array by the object which [#"Category"] to: C,D,E,F,G,H,A,B -or- C,A,B,D,E,F,G,H .
I hope it is clear what my goal is. I tried:
// sortedPosts2 = [self.objects sortedArrayUsingComparator:^(PFObject *object1, PFObject *object2) {
// return [object1[#"Category"] compare:object2[#"Category"] options:NSOrderedAscending];
// }];
// NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:category ascending:YES];
// sortedPosts2 = [self.objects sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationTop];
}
The easiest way I can think of would be a sorting block. Then you can do manual adjustments to the array compare values. This should work for any size string in Category. You may need to change around greater than signs or Ascending/Descending returns, I always get mixed up with ascending/descending...
NSArray *array;
NSString *userSelectedValue = #"C";
array = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSString *category1 = [[(NSDictionary*)obj1 objectForKey:#"Category"] lowercaseString];
NSString *category2 = [[(NSDictionary*)obj2 objectForKey:#"Category"] lowercaseString];
//Now check if either category's value is less than the user selected value
NSComparisonResult result1 = [category1 compare:[userSelectedValue lowercaseString]];
NSComparisonResult result2 = [category2 compare:[userSelectedValue lowercaseString]];
if(result1 == result2)
{
return [category1 compare:category2];
}
else if(result1 > result2)
{
return NSOrderedDescending;
}
else
return NSOrderedAscending;
}];
I want to be able to sort a NSArray of objects based on its tag value. The hitch is if the tag is 0, I want it pushed to the end of the array.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"tag" ascending:TRUE];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [self.array sortedArrayUsingDescriptors:sortDescriptors];
This returns with all the objects with tags in the front of the index (like it should).
I want a tag value > 0 to be at the front, and all the tag values of 0 at the end.
I though blocks would work, something similar to:
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDate *first = [(Person*)a birthDate];
NSDate *second = [(Person*)b birthDate];
return [first compare:second];
}];
that I found in another SO question, but unsure how to add the condition
if (obj.tag == 0) {
// push to end of array
}
Any suggestions?
You've found the idea of a comparator block; all you need to do in that block is say that an object with tag 0 sorts after anything else.
sortedArray = [self.array sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSInteger first = [a tag];
NSInteger second = [b tag];
if (first == 0) {
return (second == 0 ? NSOrderedSame : NSOrderedDescending);
}
if (second == 0) {
return NSOrderedAscending;
}
if (first < second) {
return NSOrderedAscending;
}
if (first > second) {
return NSOrderedDescending;
}
return NSOrderedSame;
}];
// sort the part without tag = 0
NSPredicate* p = [NSPredicate predicateWithFormat: #"tag != 0"];
NSSortDescriptor* sort = [NSSortDescriptor sortDescriptorWithKey: #"tag" ascending: YES];
NSMutableArray* result = [[[videos filteredArrayUsingPredicate: p]
sortedArrayUsingDescriptors: #[ sort ]] mutableCopy];
// append the part with tag = 0;
p = [NSPredicate predicateWithFormat: #"tag = 0"];
[result addObjectsFromArray: [videos filteredArrayUsingPredicate: p]];
Another approach, splice the original array to two parts, sort part without the 0s, and then append the part with 0s to the end.
Example:
NSMutable *Array1 contains 1,2.
NSMutable *Array2 contains 2,1.
Above condition should return True when we compare these two Array.Please help me in doing this.Thank you.
First sort both array in Ascending order like this
NSSortDescriptor* sortOrder = [NSSortDescriptor sortDescriptorWithKey: #"self" ascending: YES];
[array1 sortUsingDescriptors:[NSArray arrayWithObject: sortOrder]];
[array2 sortUsingDescriptors:[NSArray arrayWithObject: sortOrder]];
And then Simply compare the arrays as
return ([array1 isEqualToArray:array2]);
You could write something like:
BOOL areEqual = array1.count == array2.count;
if (areEqual) {
NSMutableArray *array3 = [NSMutableArray arrayWithArray:array2];
for (NSNumber *number in array1) {
[array3 removeObject:number];
}
if (array3.count > 0) {
areEqual = NO;
}
}
If you can assume duplicates are removed (via NSArray > NSSet) then the arrays could be compared as follows:
BOOL equal = [[NSSet setWithArray:array1] isEqualToSet:[NSSet setWithArray:array2]];
Give consideration to the size of your arrays too.
Try this one :
Here I am returning BOOL, and printing as 1 (yes), 0(no). If you want to return True and False, retrun by if-else in comparyArray:withArray: method.
- (BOOL)compareArray:(NSArray *)first withArray:(NSArray *)second{
first=[first sortedArrayUsingSelector:#selector(compare:)];
second=[second sortedArrayUsingSelector:#selector(compare:)];
return [first isEqualToArray:second];
}
- (void)anyMethod{
NSArray *arr1=#[#1,#2,#3];
NSArray *arr2=#[#3,#1,#21];
NSLog(#"Compare result is %d",[self compareArray:arr1 withArray:arr2]);
}
I have an NSMutableDictionary that maps NSString to NSString (although the values are NSStrings, they are really just integers).
For example consider the following mappings,
"dog" --> "4"
"cat" --> "3"
"turtle" --> "6"
I'd like to end up with the top 10 entries in the dictionary sorted by decreasing order of the value. Can someone show me code for this? Perhaps there is an array of keys and another array of values. However it is, I don't mind. I'm just trying to have it be efficient.
Thank you!
Get the Array of the Values, sort that array and then get the key corresponding to the value.
You can get the values with:
NSArray* values = [myDict allValues];
NSArray* sortedValues = [values sortedArrayUsingSelector:#selector(comparator)];
But, if the collection is as you show in your example, (I mean, you can infer the value from the key), you can always sort the keys instead messing with the values.
Using:
NSArray* sortedKeys = [myDict keysSortedByValueUsingSelector:#selector(comparator)];
The comparator is a message selector which is sent to the object you want to order.
If you want to order strings, then you should use a NSString comparator.
The NSString comparators are i.e.: caseInsensitiveCompare or localizedCaseInsensitiveCompare:.
If none of these are valid for you, you can call your own comparator function
[values sortedArrayUsingFunction:comparatorFunction context:nil]
Being comparatorFunction (from AppleDocumentation)
NSInteger intSort(id num1, id num2, void *context)
{
int v1 = [num1 intValue];
int v2 = [num2 intValue];
if (v1 < v2)
return NSOrderedAscending;
else if (v1 > v2)
return NSOrderedDescending;
else
return NSOrderedSame;
}
The simplest way is:
NSArray *sortedValues = [[yourDictionary allValues] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSMutableDictionary *orderedDictionary=[[NSMutableDictionary alloc]init];
for(NSString *valor in sortedValues){
for(NSString *clave in [yourDictionary allKeys]){
if ([valor isEqualToString:[yourDictionary valueForKey:clave]]) {
[orderedDictionary setValue:valor forKey:clave];
}
}
}
Use this method:
- (NSArray *)sortKeysByIntValue:(NSDictionary *)dictionary {
NSArray *sortedKeys = [dictionary keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) {
int v1 = [obj1 intValue];
int v2 = [obj2 intValue];
if (v1 < v2)
return NSOrderedAscending;
else if (v1 > v2)
return NSOrderedDescending;
else
return NSOrderedSame;
}];
return sortedKeys;
}
Call it and then create a new dictionary with keys sorted by value:
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
#"4", #"dog",
#"3", #"cat",
#"6", #"turtle",
nil];
NSArray *sortedKeys = [self sortKeysByIntValue:dictionary];
NSMutableDictionary *sortedDictionary = [[NSMutableDictionary alloc] init];
for (NSString *key in sortedKeys){
[sortedDictionary setObject:dictionary[key] forKey:key];
}
Sorting the keys and using that to populate an array with the values:
NSArray *keys = [dict allKeys];
NSArray *sKeys = [keys sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
NSMutableArray *sValues = [[[NSMutableArray alloc] init] autorelease];
for(id k in sKeys) {
id val = [dict objectForKey:k];
[sValues addObject:val];
}
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"interest" ascending:YES];
[unsortedArray sortUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];
recentSortedArray = [stories copy];
if you want to sort data in ascending order for key 'name' for such kind of Example then this may help you.
arrayAnimalList = [
{
'name' = Dog,
'animal_id' = 001
},
{
'name' = Rat,
'animal_id' = 002
},
{
'name' = Cat,
'animal_id' = 003
}
];
This is a code which help you to get sorted array
//here you have to pass key for which you want to sort data
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:descriptor];
// here you will get sorted array in 'sortedArray'
NSMutableArray * sortedArray = [[arrayAnimalList sortedArrayUsingDescriptors:sortDescriptors] mutableCopy];