Sorting arrays in Objective-C - iphone

I'm currently trying to teach myself Objective-C and was playing around with an exercise where I needed to sort an array.
I managed to complete it using the following code:
NSSortDescriptor * newSortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:TRUE];
NSArray *sortDescriptors = [NSArray arrayWithObject:newSortDescriptor];
[self.theBookStore sortUsingDescriptors:sortDescriptors];
My question is about what is actually happening here. I don't really understand exactly what I've done.
Line 1: I understand here I've created a new object that has a descriptor. This has two parameters, the column I want to sort on and that it is ascending.
Line 2: This is the line I'm confused about. Why do I need an array of sort descriptors? When I read this code I suspect it creates an array with only one row is that correct?
Line 3: I understand that this is calling the sortUsingDescriptors method but again, my confusion is why this function expects an array.
I've read the documentation but I'm really looking for a simple explanation.
Any help is much appreciated

Line 1: I understand here I've created a new object that has a
descriptor. This has two parameters, the column I want to sort on and
that it is ascending.
Really, you've created an object that is a descriptor. It describes how to sort the array.
Line 2: This is the line I'm confused about. Why do I need an array of
sort descriptors? When I read this code I suspect it creates an array
with only one row is that correct?
Right -- you've created an array that contains a single object. You could create an array that has ten or fifteen or eighty-seven sort descriptors, if you really wanted to sort on that many fields. More often, you use one, two, maybe three. So, if you're sorting a list of people, you might add sort descriptors that specify last name and first name. That way, people that have the same last name will be arranged within that group according to their first name.
Line 3: I understand that this is calling the sortUsingDescriptors
method but again, my confusion is why this function expects an array.
Again, it's so that you can have primary, secondary, tertiary (etc.) sort keys. You could have a separate method that takes a single sort descriptor instead of an array for those times when you want to sort on only one key. NSArray doesn't provide that, but you can always add it in a category if you want:
#category NSArray (SingleSortDescriptor)
- (NSArray*)sortUsingDescriptor:(NSSortDescriptor*)descriptor;
#end
#implementation NSArray (SingleSortDescriptor)
- (NSArray*)sortUsingDescriptor:(NSSortDescriptor*)descriptor
{
return [self sortUsingDescriptors:[NSArray arrayWithObject:descriptor]];
}
#end

Line 1: .. yes your right. You are creating a custom object called NSSortDescriptor. That object defines a attribute to sort after. You did enter "title". So the objects in your array-to-sort will be sorted after that property (yourObject.title "kind-of").
Line 2: Because the sorting method (sortUsingDescriptors) always needs a array, you need to create a NSArray with only one object. Okay, ... looks kind of stupid. But makes absolute sense. Lets say you would like to sort after two criteria (lets say "title", then "city").
Line 3: Yes heres must be a array because of sorting after more then one criteria.
And always keep the memory clean:
On line 1 you did allocate/init a NSSortDescriptor.
So clean up after using it (if you are not using ARC).
So add a line:
[newSortDescriptor release];

Multiple sort descriptors would be used to resolve what happens if there are multiple matches. I's a priority order. A second descriptor would tell it what to do if it found two titles the same.

Related

UISearch bar in two NSMutables arrays

I see item UISearchBar search two arrays and very much items and not found solution, the problem its similar, have two NSMutablesArrays "subdetail" and "sublista" its show in Cell cell.textLabel and cell.detailTextLabel.
I try UISearchbar but i tray with NSPredicate and not run, try with NSRange and have more errors, i am desperate.PLEASE help me, any comments agree.
This its my code in Search:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
NSMutableDictionary *playas = [NSMutableDictionary dictionaryWithObjectsAndKeys:sublista, #"nombre", subdetail, #"localidad", nil];
[alldata addObject:playas];
for(NSDictionary *playas in alldata){
NSString *nombre = [playas objectForKey:#"nombre"];
NSRange nombreRange = [[nombre lowercaseString] rangeOfString:[searchText lowercaseString]];
if(nombreRange.location != NSNotFound)
[filteredList addObject:playas];
}
}
Add rest of code .m and .h
https://dl.dropboxusercontent.com/u/6217319/BuscarViewController.h
https://dl.dropboxusercontent.com/u/6217319/BuscarViewController.m
Thanks in advance.
BEST REGARDS
Your code has a lot of issues with it. I don't know which ones are actually breaking it, but any of these issues could be causing severe problems.
First, the code sample you provided doesn't provide declarations for a lot of hte objects you're referencing. No way this could possibly compile as given. If these are properties of the view controller instance, you need to use the accessor methods -- self.alldata or [self alldata], whichever you prefer.
Second, it looks like you're just adding to these properties. If you never reset their contents, every time this method is called, you're going to increase the size of your data set -- looking at your code, possibly recursively.
Third, you try to merge the two datasets together, and then try to search through only one of them. Either don't merge, or search through both seperately and then merge the results. As it is, what you're doing won't work.
Fourth, your table view should really only be displaying one type of data, so you shouldn't need to merge.
Edit:
Based on the code samples you've provided, your entire VC is going to need restructuring. Given how much of your code is written in what appears to be spanish, I'm doing a bit of guesswork at what you're actually doing.
First off, assuming you're using a modern version of xcode, get rid of the #synthesize in the .m file (it's no longer needed anymore). That will cause every single place you're using the actual ivar instead of a proper getter to turn into an error, so you can fix them quickly. iVars will by default use a prefixed underscore of their property name, so you can still access them if you have to -- but only by explicitly accessing the ivar instead of the property.
Second, you should restructure how you handle the data. I don't know where you get your data, but it looks like the various objects are fairly consistent. You should go ahead and either create a new class to hold all the data, or just put them all into a single dictionary. At that point, the 'alldata' property should, in fact, be an array of all valid data. What you should do is then have a filtered list of data (filteredData would be a good name), and you place whatever data matches the search criteria in there. Just remember to either reload the table or update it appropriately as items move into and out of the filtered list.

Checking if NSMutableArray contains values from another array

I have an 3 NSMutableArray objects that contain CMTime objects. How can I iterate through all three of them in an efficient manner and find out if there are duplicate values in all three? For example, I'm iterating through one of time and reading the value and storing it in x. Now, I want to see if x occurs (at any position) within the other two arrays. I tried looking for a contains method, but couldn't find one. I did come across filterUsingPredicate, but I'm not sure if this is the best way of doing it nor how to actually use predicates.
I tried looking for a contains method, but couldn't find one.
Use indexOfObject:
like this:
if ([array indexOfObject:object] != NSNotFound) {
// object found
}
else {
// object not found
}
You can use ([yourArray indexOfObject:x] != NSNotFound) in place of your missing contains method. However, if you're doing this quickly, often, or with a lot of elements, you should consider using NSMutableOrderedSet, which is ordered like NSMutableArray, but offers a quick and efficient contains method, as well as allowing quick operations like union and intersection, which might allow you to redesign your algorithm to iterate through your elements much less.

Source Code for Two Dimmensional Array in i for iPhone sdk

I want to create meachanical units convertor calculator in iphone sdk so i have to perform one to many type of operation. for example Length is category and there is multiple type of units in Length category for ex.meter,kilometer etc.Now for every unit i will have to create multiple combinations for that i'm using if-else conditions for now to work but practially this increases my code a lot because as there are almost 30 categories and each category has multiple units.So is there any another way to solve this problem in short way as it is too hectic to write so many if else combinations in my code. For this i thought that it might be possible to use two dimensional array.so please provide me code for two dimensional array to perform this calulation operation.
Just put NSArray objects in an NSArray and you have your 2 dimenensional array. (pretty much like in any other language.)
NSMutableArray * myTwoDimensionalArray = [NSMutableArray alloc]init];
[myTwoDimensionalArray addObject:[NSArray arrayWithObjects:#"value 0/0", #"value 0/1",nil]];
[myTwoDimensionalArray addObject:[NSArray arrayWithObjects:#"value 1/0", #"value 1/1",nil]];
// to get value at [i][j]
[[myTwoDimensionalArray objectAtIndex:i] objectAtIndex:j];
As jules has suggested you can use a NSMutableArray yo create your 2-d array. Another approach would be to have mXn number of objects in a single NSMUtableArray. Create a array and add objects sequentially. Access the [i][j] element by accessing the object at (i*n)+j.

adding objects to Mutable array

I want to add items to mutable array from a dictionary. Problem is I want to check existing array items before adding new item. If same item is already there in the array, I want to replace it. else add the new item.
How could I do it?
You could perhaps use an NSMutableSet rather than an NSMutableArray. The addObject method on NSMutableSet will only "add a given object to the set, if it is not already a member."
If you'd like to check membership before adding to the set anyway, you can check the result of:
[mySet containsObject:myObjectFromDictionary]
...which returns a simple BOOL value indicating whether the set already contains an object whose isEqual method returns true when your object is passed to it.
(For a little extra functionality, NSCountedSet will keep track of the number of objects added to the "set" for which isEqual: returns true)
You could compare the result of : [yourArray indexOfObject:yourObject]; against NSNotFound to know if the object is in the array.
It will give you the index of the object to replace, or if it is equal to NSNotFound, you will add it.
Objects equality is tested with isEqual: method.
NSArray class reference.
On the face of it, both Vincent's and Rich's answers are correct.
However, there is a conceptual issue in the original question that hasn't been addressed.
Namely, that "membership in an array" via indexOfObject: (or containsObject: in a set) is ultimately done by comparing the two objects using isEqual:.
If isEqual: returns YES, then the two objects better had damned well be functionally identical in your code or else you have other, significantly more serious, problems in your design and implementation.
Thus, the real question should be "How do I detect if an object is already in an array and not add it?" and Rich's and Vincent's answer are both still correct.
I.e. you should only need to check for presence and, if present, take no action.
(Note that there are esoteric situations where replacement is actually warranted, but they are both truly esoteric and not generally used within the context of a mutable collection)

Sorting an array with instances of a custom class

I have an array filled with instances of a custom class which contains two String properties, firstname and lastname. Both have a getter method which is equal to the name of the property itself. There is also a method for retrieving the Full name of a person called "getFullName". Consider the example below.
CustomClass *person = [[CustomClass alloc] ...];
person.firstname // Returns "Thomas"
person.lastname // Returns "Meier"
[person getFullName] // Returns "Thomas Meier"
Now I would like to sort this Array by Fullname in a descending Order. I have been looking at some array sorting methods but was not quite able to figure out how to go about this. I guess that I have to create some kind of comparison function which compares two elements, yet how do I tell the SDK which values to pass to this method and where should I place it (in the custom class or in the class where the sorting happens?). Maybe there is another/better way of going about this? Admittedly I have close to none experience with sorting arrays.
Thanks a lot for your help!
Ps. The code should run on iOS 3.2
There are a couple ways to do this. One is to put a comparison method on the custom class. Call it -compare: or something like that. That method should take another object of the same custom type as its input. It should return NSOrderedAscending, NSOrderedDescending, or NSOrderedSame, depending on the result of the comparison. (Inside this compare function is where you look at your own fullName versus the passed-in object's fullName.)
Then you can use NSMutableArray's -sortUsingSelector: method, like this:
[myArray sortUsingSelector:#selector(compare:)];
This works on all versions of iOS. There are block comparison methods available in 4.0+.