array sorting error in objective c - ios

I have 4 values in my NSDictionary below which are 1000,640,80 and 0
It sorts the non-zero values correctly but it always gives 0 as greater than all the other values like (descending): 0,1000,640,80 Here's the code:
NSMutableDictionary *dict = [[self model] stateFromDocumentNamed:#"state"];
NSArray *values=[dict allValues];
NSMutableArray *mutvalues = [(NSArray*)values mutableCopy];
[mutvalues sortUsingSelector:#selector(compare:)];
values=[[values reverseObjectEnumerator] allObjects];
NSLog(#"%#",mutvalues);

Presumably you are comparing strings which contain numbers. To have the sort work as you expect with the numbers you will want to use the NSNumericSearch option (in the method compare:options:, probably used with sortedArrayUsingComparator:).

This is probably because the objects in your NSMutableDictionary are strings instead of numbers. Possible solutions:
You would need to convert all objects to numbers
Use a different selector to sort
sort using a block, using sortedArrayUsingComparator
EDIT: sort using method proposed in Wain's answer

Related

How to add two array's objects as objects and keys to the third array in Objective C

I am trying to add two arrays into the third array i.e one array's objects are values to the third array and other array's objects are keys to the third array and I am getting the output as null , Is this a right way to do.
NSArray *newcontactkeys,*newcontactvalues ;
NSMutableArray *autoSyncDataArray;
newcontactkeys=[self.resultDict objectForKey:#"keys"];
newcontactvalues=[self.resultDict objectForKey:#"values"];
[autoSyncDataArray setValue:[self.resultDict objectForKey:#"values"]
forKey:[self.resultDict objectForKey:#"Keys"]];
NSLog(#"autosyncArray is %#",autoSyncDataArray);
Output: autosyncArray is (null)
You are using an array, which is an indexed collection, but talking about keys, dictionaries are keyed collections.
NSDictionary has a class method to directly create a dictionary from two arrays, use this and your code becomes, updating to modern Obj-C syntax:
NSArray *newContactKeys = self.resultDict[#"keys"];
NSArray *newContactValues = self.resultDict[#"values"];
NSDictionary *autoSyncDataDict = [NSDictionary dictionaryWithObjects:newContactValues
forKeys:newContactsKeys];
HTH
You're not initialising your array.
NSMutableArray *autoSynchDataArray = [NSMutableArray new]
Also use addObject instead of set value:
[autoSyncDataArray addObject:[self.resultDict objectForKey:#"values"]
You cannot join/Manipulate multiple Array of type NSArray.
Create a NSMutableArray which allows reordering and manipulation of data in it. You can add any number of objects to it, rearrange it and delete it.
NSMutableArray *templateArray = [NSMutableArray new];
There are 2 issues:
Null issue: You are not initializing array. So you will have to use below statement:
NSMutableArray *autoSyncDataArray = [[NSMutableArray alloc] init];
Key/Value Pair: If you want to put keys and values in an array. It will not work like Dictionary. It will go into sequential form. If you are ok with sequential form then use:
[autoSyncDataArray addObject:[self.resultDict objectForKey:#"keys"]];
[autoSyncDataArray addObject:[self.resultDict objectForKey:#"values"]];
otherwise use:
NSMutableDictionary *autoSyncDataDict = [[NSMutableDictionary alloc] init];
[autoSyncDataArray setValue:[self.resultDict objectForKey:#"values"]
forKey:[self.resultDict objectForKey:#"Keys"]];

Compare objects in two Collections

I have the following scenario:
I have two collection classes (could be NSArray, NSMutableArray, NSSet, NSOrderedSet or whatever would be best suited for this case), which hold unique objects of the same type (unique in the sense that for all objects in the collections for no two elements the isEqual method would return true).
Lets say the first collection instance holds the following objects (1,2,3,4,5) and the second one (2,3,4,6,7). Now I need a method that returns the difference between the two collections, with the extra info what exactly the difference from each collection was.
An example result for the example would be: (1,5) was removed from the first collection and (6,7) added two the second collection.
I know if I use the NSMutableArray with a sorted list and decide which list has more elements than the other, I could use removeObjectsInArray to get a list of the different objects (like described in Compare two arrays with the same value but with a different order or in How to compare and remove common objects( NSDictionaries) from 2 NSMutableArray?), but don't really know which objects was in which collection. I could create a temporary collection and put the result of removeObjectsInArray in that array and compare the other two initial arrays with the temporary array. Seems little verbose though. Is there a better way that I don't know of?
I found a much slicker way for you to do what you want by using NSPredicate. When I run the following code:
NSArray *firstArray = [[NSArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7", nil];
NSArray *secondArray = [[NSArray alloc] initWithObjects:#"1",#"2",#"3",#"8",nil];
NSArray *itemsMissingFromSecondArray = [firstArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"NOT SELF IN %#", secondArray]];
NSArray *itemsMissingFromFirstArray = [secondArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"NOT SELF IN %#", firstArray]];
NSLog(#"itemsMissingFromFirstArray=%#\nitemsMissingFromSecondArray=%#", itemsMissingFromFirstArray, itemsMissingFromSecondArray);
I get the following output showing what was missing from each array that was in the other array:
itemsMissingFromFirstArray=(
8
)
itemsMissingFromSecondArray=(
4,
5,
6,
7
)
Less code than sorting and merging, doesn't use a bunch of temporary arrays, and simple enough to read.
NOTE: If someone also wants to know the items that are in both arrays, the solution is similarly simple:
NSArray *itemsFoundInBothArrays = [firstArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF IN %#", secondArray]];
I think if you want to know the difference, you can make use of NSMutableSet and the minusSet function.
[set1 minusSet:set2];
will give you the elements in set1 but not in set2 straight away. So you don't need any temp collection and compare with original collection again.
Otherwise, if you only want to remove the elements, you can make use of NSArray and do sth like:
[secondArray removeObjectsInArray:firstArray];
Edited:
To find all the diff in one shot:
[ [set1 unionSet:set2] minusSet: [set1 intersectSet:set2] ];
+ (NSArray *) removeObjectsFromArray :(NSArray *)arrayToRemoveFrom thatAreAlsoIn:(NSArray *)arrayOfItemsToRemove
{
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:arrayToRemoveFrom];
[newArray removeObjectsInArray:arrayOfItemsToRemove];
return newArray;
}
+(void) findArrayDifferences
{
NSArray *bigArray = [[NSArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7", nil];
NSArray *smallArray = [[NSArray alloc] initWithObjects:#"1",#"2",#"3",#"8",nil];
NSArray *itemsInBigArrayThatAreNotInSmallArray = [self removeObjectsFromArray:bigArray thatAreAlsoIn:smallArray];
NSArray *itemsThatAreInBothArrays = [self removeObjectsFromArray:bigArray thatAreAlsoIn:itemsInBigArrayThatAreNotInSmallArray];
NSArray *itemsInSmallArrayThatAreNotInBigArray = [self removeObjectsFromArray:smallArray thatAreAlsoIn:itemsThatAreInBothArrays];
NSLog(#"itemsInBigArrayThatAreNotInSmallArray=%#\nitemsThatAreInBothArrays=%#\nitemsInSmallArrayThatAreNotInBigArray=%#", itemsInBigArrayThatAreNotInSmallArray, itemsThatAreInBothArrays, itemsInSmallArrayThatAreNotInBigArray);
}
This results in the following output:
itemsInBigArrayThatAreNotInSmallArray=(
4,
5,
6,
7
)
itemsThatAreInBothArrays=(
1,
2,
3
)
itemsInSmallArrayThatAreNotInBigArray=(
8
)

Sort NSMutableArray with objects [duplicate]

This question already has answers here:
How do I sort an NSMutableArray with custom objects in it?
(27 answers)
Closed 9 years ago.
Hopefully someone can help.
I'm adding multiple objects to a NSMutableArray and I need to sort the order based on the first element which will always be a number.
However I'm unsure how to do this?
For example:
NSMutableArray *array = [[NSMutableArray alloc] init];
NSArray *object = [NSArray arrayWithObjects: #"1",#"Test",#"Test"];
[array addObject:object];
Thanks
If your array always contains other arrays, and the first element of the innermost array is always a string containing a number, you could use the NSMutableArray method sortUsingComparator to sort your array:
[array sortUsingComparator: ^(NSArray* obj1, NSArray* obj2)
{
int value1 = [obj1[0] integerValue];
int value2 = [obj2[0] integerValue];
if (value1==value2)
return NSOrderedSame;
else if (value1 < value2)
return NSOrderedAscending;
else
return NSOrderedDescending;
}
];
In the sortUsingComparator family of methods, you supply a block of code that the sort method uses to compare pairs of objects in your array. The block uses the standard typedef NSComparator, which takes 2 objects as parameters and returns a value of type NSComparisonResult.
The code above will probably crash if all the objects in your array are not arrays of strings. (Actually it would work if the first element of each component array was an NSNumber, since NSNumber also responds to the integerValue message.)
If you are going to use this code in a very controlled environment where you can be sure that the data you are sorting is well-formed, it should work as written. If there is any chance that the objects in the array would be of a different type, or be empty, or that their first element would not respond to the integerValue messages, then you should add error checking code.
If you sort your array alphanumerically, the object #"1" will appear before any words. Keep in mind though that #"1" in your code above is a string, not a number.
As to how to sort an array, look into [NSArray sortedArrayUsingComparator:] and similar methods.

NSDictionary allKeys and then sorted with a selector vs keysSortedByValueUsingSelector

I am trying to get an array of all my keys in my NSDictionary into an array, and sorted using localizedCaseInsensitiveCompare. I first tried doing:
NSArray *test = [myDict keysSortedByValueUsingSelector#selector(localizedCaseInsensitiveCompare:)]];
I kept getting NSCFNumber localizedCaseInsensitiveCompare:]: unrecognized selector. I double checked and all of my 2 keys (for now) are strings.
I had to switch to doing to make it work:
NSArray *items = #[[[languages allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]];
Why is that?!
Thanks!
There is different sorting in this two cases.
NSArray *test = [myDict keysSortedByValueUsingSelector#selector(localizedCaseInsensitiveCompare:)]];
this variant sort (from docs):
Returns an array of the dictionary’s keys, in the order they would be in if the dictionary were sorted by its values.
You try to get an array, where you firstly sort values using your selector and then get list of keys. I guess, your dictionary's objects are not NSString and they don't know anything about this selector.
NSArray *items = #[[[languages allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)]];
Here you do right. You get the array of keys (which are NSString) and then sort it using right selector.
Because is keysSortedBy**Value**UsingSelector and that's why you get NSNumber exception,because is sorting by value , not by key, you have NSNumbers as values.
keysSortedby **Value** usingSelector...

What's the standard convention for creating a new NSArray from an existing NSArray?

Let's say I have an NSArray of NSDictionaries that is 10 elements long. I want to create a second NSArray with the values for a single key on each dictionary. The best way I can figure to do this is:
NSMutableArray *nameArray = [[NSMutableArray alloc] initWithCapacity:[array count]];
for (NSDictionary *p in array) {
[nameArray addObject:[p objectForKey:#"name"]];
}
self.my_new_array = array;
[array release];
[nameArray release];
}
But in theory, I should be able to get away with not using a mutable array and using a counter in conjunction with [nameArray addObjectAtIndex:count], because the new list should be exactly as long as the old list. Please note that I am NOT trying to filter for a subset of the original array, but make a new array with exactly the same number of elements, just with values dredged up from the some arbitrary attribute of each element in the array.
In python one could solve this problem like this:
new_list = [p['name'] for p in old_list]
or if you were a masochist, like this:
new_list = map(lambda p: p['name'], old_list)
Having to be slightly more explicit in objective-c makes me wonder if there is an accepted common way of handling these situations.
In this particular case Cocoa is not outdone in succinctness :)
NSArray *newArray = [array valueForKey:#"name"];
From the NSArray documentation:
valueForKey:
Returns an array containing the
results of invoking valueForKey: using
key on each of the receiver's objects.

Resources