how to sort an NSArray with a nested NSArray - objective-c

Hi I'm new with the Objective-C and i try to do some try.
I have an NSArray called "values". It is an array of array. It seems like :
["0" = > "aString",6872,5523,0091]
["1" = > "anotherString",4422,1234,0091]
["2" = > "aString",6812,2143,0314] ...
How do I sort the "values" array than the first integer value?
I should use the NSPredicate ?
please help me with some example.
thanks

Something like that with block (assuming that your integer value are NSNumber or some class that can be compared):
NSArray *sortArray = [yourArray sortedArrayUsingComparator: ^(id elt1, id elt2) {
return [[elt1 objectAtIndex:1] compare:[elt2 objectAtIndex:1]];
} ];

Related

How can I create an NSMutableDictionary from an NSMutableArray?

I'm trying to figure out the best way to sort an NSMutableDictionary. I have a dictionary of Card keys (i.e. aceSpades) that store Card values (i.e. 14). I have then been using an NSMutableArray to shuffle the 52 Card keys into an array called shuffledCards. Finally I make another array from shuffledCards thats takes a portion (15) of shuffledCards and puts them into an array called computerHand.
The new array computerHand is not good enough because I need to be able to connect the Card values with the Card keys. What I really need to do is create a new NSMutableDictionary for computerHand from the array shuffledCards so that I can sort it by Card values and still be able to retrieve the Card keys.
I'm thinking I need something like this, where currentCard is the first card of the shuffedCards array:
if (currentCard == 1) {
[compHandDictionary setObject:[[highCardDictionary
valueForKey:[shuffledCards objectAtIndex:currentCard]] intValue]
forKey:[cardsShuffled objectAtIndex:currentCard]];
}
However this is not allowed because "int" to "id" is not allowed.
There might be a better way but I have not been able to find anything. Any help would be appreciated.
...
I got this to work by modifying jstevenco's answer. I created two arrays and formed a new dictionary for the computer hand of just the 15 cards. Then to sort I used:
NSArray* sortedKeys = [newDict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
Thanks all!
You can sort a dictionary's keys using:
NSArray* sortedKeys = [[dict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
If you then want to create a sorted array from this you can use:
NSArray* objects = [dict objectsForKeys:sortedKeys notFoundMarker:[NSNull null]];
Consider using an array of dictionaries, where each dictionary contains the name and value for a given card, for example like so:
NSArray *cards = #[#{#"name" : #"Queen", #"value" : #12},
#{#"name" : #"Jack", #"value" : #11},
#{#"name" : #"Ace", #"value" : #14},
#{#"name" : #"King", #"value" : #13}];
You could then easily sort the cards array as shown below:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"value" ascending:YES];
NSArray *sortedCards = [cards sortedArrayUsingDescriptors:#[sortDescriptor]];
NSLog(#"\n\n%#\n\n", sortedCards);
Output of the NSLog statement above would be as follows:
(
{
name = Jack;
value = 11;
},
{
name = Queen;
value = 12;
},
{
name = King;
value = 13;
},
{
name = Ace;
value = 14;
}
)
To obtain an array of card names, you could then simply send a valueForKey: message to the sorted array of card dictionaries:
NSArray *sortedNames = [sortedCards valueForKey:#"name"];
NSLog(#"\n\n%#\n\n", sortedNames);
The output of the preceding NSLog statement would be:
(
Jack,
Queen,
King,
Ace
)

How to remove elements of NSDictionary

I have NSArray of NSDictionaries I need to extract 2 values or remove the values I don't need from the dictionary in the example below I need to remove id and NumberValue. any of you knows how can I do that?
Array: (
{
customerUS= {
DisplayName = "level";
InternalName = "Number 2";
NumberValue = 1;
id = xwrf
},
customerCAN= {
DisplayName = "PurchaseAmount";
InternalName = "Number 1";
NumberValue = 3500;
id = adf;
};
}
)
I'll really appreciate your help.
First thing, You can not remove/insert/update value in (immutable) NSDictionary/NSArray you need to convert NSDictionary/NSArray to (mutable) NSMutableDictionary/NSMutableArray.
such like
NSArray *myArr = ....;
NSMutableArray *newMutableArr = [myArr mutableCopy];
Then you can change in newMutableArr.
Such like
for(int i = 0 ; i < newMutableArr.count ; i ++)
{
[[newMutableArr objectAtIndex:i] removeObjectForKey:#"id"];
[[newMutableArr objectAtIndex:i] removeObjectForKey:#"NumberValue"];
}
EDITED:
Without Use of for loop and removeObjectForKey, if you have array of dictionary and both are mutable then you can also delete a key and its object from all elements of the array like this:
[newMutableArr makeObjectsPerformSelector:#selector(removeObjectForKey:) withObject:#"id"];
[newMutableArr makeObjectsPerformSelector:#selector(removeObjectForKey:) withObject:#"NumberValue"];
I would advice you to read Apple documents.
For modifying any Collection object after it is created, you need the mutable version.
For NSDictionary we have NSMutableDictionary. Read here.
We have a method for removing objects:
- (void)removeObjectForKey:(id)aKey
There are other methods as well. You can easily refer them in the above mentioned documentation.
Find out removeObjectForKey for deleting record from NSMutabledictionary.
removeObjectForKey pass the key value whatever you have like
all this are your key
DisplayName,
InternalName,
NumberValue,
id
do like this
removeObjectForKey:#"id";
First of all you have to convert the array to mutable array and then you can remove the key-value pairs from dictionary.
NSMutableArray *mutableArray = [yourArray mutableCopy];for(int i=0;i<mutableArray.count;i++){ NSMutableDictionary *outerDictionary = [mutableArray objectAtIndex:i]; for(NSString *key in outerDictionary.allKeys){ NSMutableDictionary *innerDictionary = [outerDictionary objectForKey:key]; [innerDictionary removeObjectForKey:#"id"]; [innerDictionary removeObjectForKey:#"NumberValue"]; }
}

Flatten an NSArray

I have an array like this:
array: (
(
"http://aaa/product/8_1371121323.png",
"http://aaa/product/14_1371123271.png"
),
(
"http://aaa/product/9_1371121377.png"
)
)
and I have to create another array from that one like this
array: (
"http://aaa/product/8_1371121323.png",
"http://aaa/product/14_1371123271.png",
"http://aaa/product/9_1371121377.png"
)
How can I do that? Is it possible to combine all the objects and separate them using some string?
It can be done in a single line if you like key-value coding (KVC). The #unionOfArrays collection operator does exactly what you are looking for.
You may have encountered KVC before in predicates, bindings and similar places, but it can also be called in normal Objective-C code like this:
NSArray *flatArray = [array valueForKeyPath: #"#unionOfArrays.self"];
There are other collection operators in KVC, all prefixed with an # sign, as discussed here.
Sample Code :
NSMutableArray *mainArray = [[NSMutableArray alloc] init];
for (int i = 0; i < bigArray.count ; i++)
{
[mainArray addObjectsFromArray:[bigArray objectAtIndex:i]];
}
NSLog(#"mainArray :: %#",mainArray);
Sample code:
NSArray* arrays = #(#(#"http://aaa/product/8_1371121323.png",#"http://aaa/product/14_1371123271.png"),#(#"http://aaa/product/9_1371121377.png"));
NSMutableArray* flatArray = [NSMutableArray array];
for (NSArray* innerArray in arrays) {
[flatArray addObjectsFromArray:innerArray];
}
NSLog(#"%#",[flatArray componentsJoinedByString:#","]);
NSMutableArray *arr1 = [NSMutableArray arrayWithArray:[initialArray objectAtIndex:0]];
[arr1 addObjectsFromArray:[initialArray objectAtIndex:1]];
Now arr1 contains all the objects

NSArray sorted by function

I have an NSArray containing several NSDictionary instances. Each NSDictionary has, among other fields, an object named rating and one numberOfVotes(both are int). How can I sort the array so it gets sorted by rating/numberOfVotes? More generically, can I sort it by doing an operation like mentioned above? Or would it be better to just add another object to each NSDictionary with the value of each operation and then sort by that?
Thanks
EDIT - I have added the following. Still not sorting properly. One question: Should this work for more than 2 objects in my array. (The number of objects will vary)
[sortedArray sortedArrayUsingComparator:^NSComparisonResult(id dict1, id dict2)
{
MyObj *obj1 = (MyObj *)dict1;
MyObj *obj2 = (MyObj *)dict2;
int rating1 = obj1.rating.intValue;
int rating2 = obj2.rating.intValue;
int number1 = obj1.number_of_votes.intValue;
int number2 = obj2.number_of_votes.intValue;
double key1 = ((double)rating1)/number1;
double key2 = ((double)rating2)/number2;
if (key1 < key2)
{
return NSOrderedDescending;
}
if (key2 < key1)
{
return NSOrderedAscending;
}
return NSOrderedSame;
}];
You can define a custom comparator to use a composite sorting key of the kind that you are looking for. If there is no good reason to have that sorting key in the dictionary, other than performing the sort, do not add an item to the dictionary.
array = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
int rating1 = [[obj1 objectForKey:#"rating"] intValue];
int numberOfVotes1 = [[obj1 objectForKey:#"numberOfVotes"] intValue];
int rating2 = [[obj2 objectForKey:#"rating"] intValue];
int numberOfVotes2 = [[obj2 objectForKey:#"numberOfVotes"] intValue];
double key1 = ((double)rating1)/numberOfVotes1;
double key2 = ((double)rating2)/numberOfVotes2;
if (key1 > key2) {
return (NSComparisonResult)NSOrderedDescending;
}
if (key1 < key2) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
Note: The sortedArrayUsingComparator: method does not sort the array in place; instead, it returns a sorted copy. If you would like an in-place sorting, use NSMutableArray.
The adequate way would be using blocks like this
NSArray *sortedArray;
sortedArray = [unsortedArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
float first = [[(NSDictionary*)a objectForKey:#"rating"] floatValue]/
[[(NSDictionary*)a objectForKey:#"numberOfVotes"] floatValue];
float second = [[(NSDictionary*)a objectForKey:#"rating"] floatValue]/
[[(NSDictionary*)a objectForKey:#"numberOfVotes"] floatValue];
return [[NSNumber numberWithFloat:first] compare: [NSNumber numberWithFloat:second]];
}];
you may find more ways to compare:
How to sort an NSMutableArray with custom objects in it?
The family of methods you seek are prefixed with sortedArray.
For a function (which is one of multiple options), see: -[NSArray sortedArrayUsingFunction:context:].
Edit: If you want to do rating divided by numberOfVotes, you will have to sort by a function or comparator block or replace the dictionary with a model object which has a method to calculate rating / numberOfVotes.
Use NSSortDescriptor.
NSArray *sorted = [array sortedArrayUsingDescriptors:[NSArray arrayWithObjects:
[NSSortDescriptor sortDescriptorWithKey:#"rating" ascending:YES],
[NSSortDescriptor sortDescriptorWithKey:#"numberOfVotes" ascending:YES],
nil]
];
Filtering data is one of the essential tasks in computing.
You can sort it several ways.
NSPredicate
You can see examples here
NSSortDescriptor
You can see examples here
Regular Expressions
Set Operations
Key-Value Coding
Ideally, you should substitute NSDictionary by a custom object, with properties like rating and numberOfVotes. Then, you could declare a method compare: on this custom object and use as the selector to sort the array.
You can use a block code to sort the objects but abstracting the implementation into a custom object is much cleaner.
you can use NSSortDescriptor here for sorting for example your array that containing several NSDictionnaries name is dataArray.
NSSortDescriptor * descriptor = [[NSSortDescriptor alloc] initWithKey:rating
ascending:YES];
NSArray * keyArrray = [NSArray arrayWithObjects:descriptor, nil];
NSArray * sortedArray = [dataArray sortedArrayUsingDescriptors:keyArrray];
With the help of NSSortDescriptor we can sort any data type key value pair.

writing a plist in objective c

I know there are many topics with similar issues, but I have not been able to find a topic addressing my question.
I want to store a plist of highscores.
Every entry of highscores must have two elements
an NSString* and an int.
I want to store the top 20 high scores (pairs of strings and ints) and do that in a plist.
I start with:
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile: [[NSBundle mainBundle] pathForResource:#"Mylist" ofType:#"plist"]];
I want the item 0 of the array to be a dictionary, where I can insert key value pairs of
(string, int)
How do I do that?
You can always call [arr addObject:score];, sort it, and remove the final item until there are 10.
To sort:
[arr sortUsingComparator:^(id firstObject, id secondObject) {
NSDictionary *firstDict = (NSDictionary *)firstObject;
NSDictionary *secondDict = (NSDictionary *)secondObject;
int firstScore = [[firstDict objectForKey:#"score"] intValue];
int secondScore = [[secondDict objectForKey:#"score"] intValue];
return firstScore < secondScore ? NSOrderedAscending : firstScore > secondScore : NSOrderedDescending : NSOrderedSame;
}];
If you want the scores to be the other way around, change the '>' to '<' and vice-versa. To keep the list down to 10:
while ([arr count] > 10) {
[arr removeLastObject];
}
You may have to sort when you load from your plist. For 10 scores the performance hit will be minimal, so I suggest you do it just in case.
Property List Serialization
You will want to make notice of: the mutability option, as your method probably returns immutable arrays...
storing in a plist is done with the writeToFile:... or writeToURL:... methods
[arr insertObject:[NSMutableDictionary dictionary] atIndex:0];