Sort Array by Key - iphone

I have two arrays used in a small game.
If the player gets a score above a certain value their name & score gets output via
an UILabel.
NSArray *namesArray = [mainArray objectForKey:#"names"];
NSArray *highScoresArray = [mainArray objectForKey:#"scores"];
I need the UILabels to display with the highest score in descending order, with the corresponding name. I've used an NSSortDescriptor to sort the score values numerically.
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"self"
ascending:NO] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedScore = [[NSArray alloc]init];
sortedScore = [scoresArray sortedArrayUsingDescriptors:sortDescriptors];
NSMutableArray *scoreLabels = [NSMutableArray arrayWithCapacity:10];
[scoreLabels addObject:scoreLabel1];
......
NSUInteger _index = 0;
for (NSNumber *_number in sortedScore) {
UILabel *_label = [scoreLabels objectAtIndex:_index];
_label.text = [NSString stringWithFormat:#"%d", [_number intValue]];
_index++;
}
This works well enough as the scores now display in descending order.
The problem is that I need the corresponding name to also display according in the new sorted order.
I cant use the same sort selector and I don't wont to sort them alphabetically, they need
to correspond to the name/score values that were first input.
Thanks in advance

You need to put the name and the score together into a single instance of NSDictionary, and then have an NSArray of those NSDictionary instances. Then when you sort by score, you can pull up the corresponding name.

Related

Delete only one item from array having same multiple values

There is an array in my app having multiple same values in it. I need to delete only one value at a time from array whether it has same more values in it.
Level1 Business,
Level2 Economy,
Level2 Economy,
Level1 Business
How this can be achieved, and main thing is that these values are dynamic these can be more or less also. Please guide for above.
Below is what i tried.
if([arr containsObject:[NSString stringWithFormat:#"%d",ind]]){
[arr removeObject:[NSString stringWithFormat:#"%d",ind]];
}
This thing removes all similar entries, not required. Thanks in advance.
try like this,
NSArray *array = [NSArray arrayWithObjects:#"Level1 Business", #"Level2 Economy", #"Level2 Economy", #"Level1 Business", nil];
NSMutableArray *mainarray=[[NSMutableArray alloc]initWithArray:array];
int n=[mainarray indexOfObject:#"Level2 Economy"];//it gives first occurence of the object in that array
if(n<[mainarray count]) // if the object not exist then it gives garbage value that's why here we have to take some condition
[mainarray removeObjectAtIndex:n];
NSLog(#"%#",mainarray);
O/P:-
(
"Level1 Business",
"Level2 Economy",
"Level1 Business"
)
As you say,
[array removeObject:#"SomeObject"];
removes all instances of where isEqual: returns YES. To remove only the first instance, you can use something like
NSUInteger index = [array indexOfObject:#"SomeObject"];
if(index != NSNotFound) {
[array removeObjectAtIndex:index];
}
Use [arr removeObjectAtIndex:yourIndex ] to remove your object at perticular postion at dynamic
Sample Code :
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:#"hello",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",nil];
NSUInteger obj = [arr indexOfObject:#"hi"]; //Returns the lowest integer of the specified object
[arr removeObjectAtIndex:obj]; //removes the object from the array
NSLog(#"%#",arr);
In your Case :
if([arr containsObject:[NSString stringWithFormat:#"%d",ind]])
{
NSUInteger obj = [arr indexOfObject:[NSString stringWithFormat:#"%d",ind]]; //Returns the lowest integer of the specified object
[arr removeObjectAtIndex:obj];
}
Here your requirement is like definition of NSSet, which contains unique objects only.
But this will implies only if both the same value objects, are really in referring to same memory location as well.
If this is the case then and then, you can try code mentioned below:
// create set from an array
NSSet *telephoneSet = [NSSet setWithArray: myArray];
// create array from a set
NSMutableArray *array = [NSMutableArray arrayWithArray:[set allObjects]];
I don't know whether it will work for your requirement or not. But for that, it would be required to check the object equality level.
Still it might help you as an less line of code.
NSMutableArray *uniques= [[NSMutableArray alloc] init];
for (NSString *word in duplicateWordsArray){
if (!uniques.contains(word)){
[ uniques addObject:word];
}
}
I wrote this from my phone so it isn't formatted for code, but this will do it for you quickly and you'll have an array (uniquearray) that has unique words. Then you can use that one or set your original array = to unique array
NSArray *input = [NSArray arrayWithObjects:#"Level1 Business", #"Level2 Economy", #"Level2 Economy", #"Level1 Business", nil];
NSMutableArray *output = [[NSMutableArray alloc] init];
[output addObject:[input objectAtIndex:0]];
for(NSString *value in input) {
if(![output containsObject:value])
[output addObject:value];
}

Sorting Multiple NSMutableArray's

I have 3 MutableArray's Named:
tvShows
tvNetworks
tvdbID
I need to sort them by the name of the tvShows.
But the need to stay linked.
So e.g.:
tvShows = Breaking Bad, House, Community;
tvNetworks = AMC, FOX, NBC;
tvdbID = 81189, 73255, 94571;
Needs To Become:
tvShows = Breaking Bad, Community, House;
tvNetworks = AMC, NBC, FOX;
tvdbID = 81189, 94571, 73255;
How would I do this? It's my first app so sorry if it's a realy easy question.
store them in an array of dictionaries then sort with an NSArray sort function: (below)
NSDictionary * dict1 = #{#"title":#"breaking bad",#"network":#"AMC",#"tvbdID":#(81189)};
NSDictionary * dict2 = #{#"title":#"house",#"network":#"FOX",#"tvbdID":#(73255)};
NSDictionary * dict3 = #{#"title":#"Community",#"network":#"NBC",#"tvbdID":#(94571)};
NSArray * array = #[dict1,dict2,dict3];
NSSortDescriptor * desc = [NSSortDescriptor sortDescriptorWithKey:#"title"ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray * sortedArray = [array sortedArrayUsingDescriptors:#[desc]];
I would personally create a custom NSObject called TVShow, that has properties of showName, network, and tvbdID. This way, you only have one array of each show. Assuming your array is called myShows, you could do something like this:
[allShows sortUsingComparitor:^NSComparisonResult(id a, id b) {
NSString *firstName = [(TVShow*)a showName];
NSString *secondName = [(TVShow*)b showName];
return [firstName compare: secondName];
}];
That is, if you wanted to sort by show name. You can swap network for showName if you wanted to sort by network!
No idea what your end goal is, but you should probably create a TVShow class that has properties (i.e., instance variables) for "title," "network", and "dbid." Then you can instantiate three TVShow objects with their appropriate properties, put them in a mutable array, and use one of the sorting methods on NSMutableArray -- I'd probably choose sortUsingComparator:.
you can't do it with 3 independent arrays but maybe with 1 dictionary where the keys are tv shows and the value is a dictionary with 2 keys: tvNetworks & tvdbIDs
sample:
NSDictionary *data = #{#"Breaking Bad":#{#"tv" : #"AMC", #"tvdb": #(81189)},
#"House":#{#"tv" : #"FOX", #"tvdb": #(73255)},
#"Community":#{#"tv" : #"NBC", #"tvdb": #(94571)}};
NSArray *sortedShows = [data.allKeys sortedArrayUsingSelector:#selector(compare:)];
for (id show in sortedShows) {
NSLog(#"%# = %#", show, data[show]);
}
One of the easiest and most straightforward ways to do this would be to create one array of dictionaries, like this:
NSMutableArray *tvShowInfos = [NSMutableArray array];
for (NSInteger i = 0; i < tvShows.count; i++) {
NSDictionary *info = #{#"show": [tvShows objectAtIndex:i],
#"network": [tvNetworks objectAtIndex:i],
#"id": [tvdbIDs objectAtIndex:i]};
[tvShowInfos addObject:info];
}
You can then sort that array easily:
[tvShowInfos sortUsingDescriptors:#[ [[NSSortDescriptor alloc] initWithKey:#"show" ascending:YES] ]];
If you need an array that contains all networks, sorted by show title, you can then use valueForKey: on the array of dictionaries:
NSArray *networksSortedByShow = [tvShowInfos valueForKey:#"network"];

Use existing NSArray object properties to create a new NSArray for sectioned tableView

So I have the kind of classic situation where I want to group my tableView by Month/Year. I have a member of my conference object called beginDateSearchString that I use to put different conference into buckets; my problem is in the next part where I try and fail to use a NSSortDescriptor to sort each bucket by beginDate (which is a date).
I am getting an error related to unsorted not being able to receive sort descriptor type selectors.
Here is the disgusting code:
- (NSArray *)arrayOfDateSortedEvents {
NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
//place into buckets
for (WSConference *conference in self.arrayOfEvents) {
if (![dictionary objectForKey:[conference beginDateSearchString]]) {
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:conference,nil];
[dictionary setObject:array forKey:[conference beginDateSearchString]];
}
else {
[[dictionary objectForKey:[conference beginDateSearchString]] addObject:conference];
}
}
//sort each bucket by descriptor beginDate
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"beginDate" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:descriptor];
for (NSMutableArray *unsorted in dictionary) {
[unsorted sortUsingDescriptors:sortDescriptors];
}
// now, unkey and add dictionary in order
while ([dictionary count] > 0) {
NSString *lowest = nil;
for (NSMutableArray *array in dictionary) {
if (!lowest)
lowest = [[dictionary allKeysForObject:array] objectAtIndex:0];
else {
if ([(WSConference *)[array objectAtIndex:0] beginDate] < [[dictionary objectForKey:lowest] beginDate])
lowest = [[dictionary allKeysForObject:array] objectAtIndex:0];
}
}
[sortedArray addObject:[dictionary objectForKey:lowest]];
[dictionary removeObjectForKey:lowest];
}
return sortedArray;
}
You want to probably filter the array in addition to sorting. See NSPredicate and the NSArray method -filteredArrayUsingPredicate: Then create an eventsByDateArray of the eventArrays created by the filter. Then in your table view delegate for creating the cells, if everything is ordered properly, the first section would represent the date of the events in the eventArray that is the first object of the eventsByDateArray and the table rows would consist of the events in the eventArray. And so on for each date.
Added
Your fast enumeration is incorrect. You enumerate through the keys of the dictionary. So in your code unsorted equals each of the keys as it enumerates. This is a GREAT lesson to everyone. It does not matter how you 'type' a variable. When Objective-C compiles it turns them all into id. So NSMutableArray *unsorted is not an NSMutableArray unless it is assigned to an NSMutableArray. If you assign unsorted to an NSString it will be an NSString. The fast enumerator for a dictionary works using the keys. So, in this case, unsorted becomes an NSString.
Instead of:
for (NSMutableArray *unsorted in dictionary) {
[unsorted sortUsingDescriptors:sortDescriptors];
}
you should have this:
for (id key in dictionary) {
NSMutableArray *unsorted = [dictionary objectForKey:key];
[unsorted sortUsingDescriptors:sortDescriptors];
}

Sort an array with numeric strings

Hello I have an array of persons, and i am trying to sort them by age using a sort descriptor.
The age field in a patient is a string so when calling:
ageSorter = [[NSSortDescriptor alloc] initWithKey:#"age" ascending:YES];
[personList sortUsingDescriptors:[NSArray arrayWithObject:ageSorter]];
It sorts them but 100 appears first because its is not using numericSearch in the compare options.
Is there a ways i can still sort with descriptor but maybe using a selector to change how to compare the strings?
The finderSortWithLocale method (both these are taken from apple api):
int finderSortWithLocale(Person *person1, Person *person2, void *locale)
{
static NSStringCompareOptions comparisonOptions = NSNumericSearch;
NSRange string1Range = NSMakeRange(0, [string1 length]);
NSString *age1 = person1.age;
NSString *age2 = person2.age;
return [age1 compare:age2
options:comparisonOptions
range:string1Range
locale:(NSLocale *)locale];
}
How to call this method (edited: call the function on array of Persons):
NSArray *sortedArray = [personList sortedArrayUsingFunction:finderSortWithLocale
context:[NSLocale currentLocale]];
I also faced the same issue and found answer here.
Instead of NSString comparison, do with your object property. i.e for age.
Example. : In ascending order :
NSArray *sortedArray = [_arrayCaptureLeadList sortedArrayUsingComparator:^(Person *obj1, Person *obj2) {
return [obj1.age compare:obj2.age options:NSNumericSearch];
}];
NSMutableArray *filterResultArray = [NSMutableArray arrayWithArray:sortedArray];
In descending order :
NSArray *sortedArray = [_arrayCaptureLeadList sortedArrayUsingComparator:^(Person *obj1, Person *obj2) {
return [obj2.age compare:obj1.age options:NSNumericSearch];
}];
NSMutableArray *filterResultArray = [NSMutableArray arrayWithArray:sortedArray];
I know this is very late to reply your question but may this will be helpful for others. ^_^
You could create a category on NSString that adds a method numericCompare: and which calls [self compare:otherString options:NSNumericSearch]. Another option is to convert the age field into a NSNumber instead of a NSString. Yet another option involves a NSComparator block and sortUsingComparator.

Sorting NSSets of a core data entity - Objective-C

I would like to sort the data of a core data NSSet (I know we can do it only with arrays but let me explain...). I have an entity user who has a relationship to-many with the entity recipe. A recipe has the attributes name and id.
I would like to get the data such that:
NSArray *id = [[user.recipes valueForKey:#"identity"] allObjects];
NSArray *name = [[user.recipes valueForKey:#"name"] allObjects];
if I take the object at index 1 in both arrays, they correspond to the same recipe...
Thanks
You need to sort the recipes first:
NSArray *sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]];
NSArray *sortedRecipes = [[recipes allObjects] sortedArrayUsingDescriptors:sortDescriptors];
you can then extract an array of attributes from the sorted recipes array and the results will remain in sorted order:
NSArray *sortedNames = [sortedRecipes valueForKey:#"name"];
NSArray *sortedIdentities = [sortedRecipes valueForKey:#"identity"];
If you want them to be in the same order, then you need to sort them before extracting the values. Example:
NSArray * sortedRecipes = [user.recipes sortedArrayUsingDescriptors:arrayOfSortDescriptors];
NSArray * identities = [sortedRecipes valueForKey:#"identity"];
NSArray * names = [sortedRecipes valueForKey:#"name"];
EDIT
My apologies. I just realized this is an iPhone question, and NSSet doesn't have sortedArrayUsingDescriptors: on the iPhone. However, it's trivial to work around:
NSArray * recipes = [user.recipes allObjects];
NSArray * sortedRecipes = [recipes sortedArrayUsingDescriptors:arrayOfSortDescriptors];
....