Is there any built in method for sorting in Objective-c? - objective-c

I have two sorted NSMutableArrays (or I can use any other collection, not critical), I need to insert objects from the first array to the second and preserve sort order in the second array. What is the optimal (fastest) method to do that? I can implement all the known good algorithms, but my question is, if there is already some built-in method? If not, what is the best algorithm in my case?

The real answer would be: it depends, since you are asking: what is the fastest way of inserting objects from one array into another while preserving sort order.
There is no built in way of inserting in the right place of a sorted array. You can achieve the same effect by just adding the two arrays together but it won't be "the fastest way".
What is actually faster depends on many things like: how much data does the arrays contain, what is the ratio of data in array1 vs array2 (does one array contain much more data than the other)?, etc.
NOTE: You should probably begin with the simple solution and only optimize once you experience performance problems. Do measurements with a large data set though, to see that your solution works with whatever data your users may have.
Inserting items from one sorted array into another sorted array
If you want to merge the two arrays by inserting objects in the right place then normal algorithms apply. You should insert the smaller array into the bigger array and try to insert entire sorted sequences where possible instead of every item one by one.
For best performance you should try to make a batch insert using insertObjects:atIndexes: instead of inserting the object one by one.
You can use indexOfObject:inSortedRange:options:usingComparator: to find the index that each item should be inserted in the other array if you specify NSBinarySearchingInsertionIndex for the options. Also, the comparator you are using must be the same as the comparator that sorted the array, otherwise the result is "undefined".
With this in mind you would do something like this
Create mutable index
For every ITEM in SMALLER ARRAY
Find the index where to insert ITEM in LONGER ARRAY
Add (the insertion location + the location in the short array) as the index in the mutable set.
Next item.
Batch insert all items.
The documentation for insertObjects:atIndexes: tells you that "the corresponding location specified in indexes after earlier insertions have been made." Which in your case with two sorted array mean all items with a lower index will already have been added and thus you should add the index of the object in the short array to the value returned from indexOfObject:inSortedRange:options:usingComparator:.
Another (probably very premature optimization) you can do is decrease the sortedRange for every item in the loop so that you don't have to search through parts of the array that you know the item to be inserted is bigger than.
There are probably many other optimizations that can be made. You should still measure first! Hopefully this will get you started.

NSArray *newArray=[firstArray arrayByAddingObjectsFromArray:secondArray];
newArray = [newArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];

I would start by simply adding all of the objects of the first array to the second and then resorting the second. Time how long it takes. If it is acceptable, stop there.
If not, you could try a binary search to find the insertion point in the second array for each item in the first array. Since both arrays are sorted, you might be able to optimise the search by using the last insertion point as the lower bound each time round. Something like this:
NSInteger insertionPoint = -1;
for (id object in array1)
{
insertionPoint = [self binarySearch: array2 for: object lowerBound: insertionPoint + 1];
[array2 insertObject: object atIndex: insertionPoint];
}

The Cocoa class NSSortDescriptor together with sortedArrayUsingDescriptors: from NSArray should do what you are after.
Since you are using mutable arrays, you might want to use sortUsingDescriptors: which sorts the mutable array without creating a new one.

Look at the documentation here to see if any of the NSArray sort methods work for you. http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html. You can scroll down to the methods and there's 7 built-in ones for sorting. You could probably just combine the two arrays and run the sortedArrayUsingComparator: or one of the other methods.

Related

Keeping an array sorted - at setting, getting or later?

As an aid to learning objective c/oop, I'm designing an iOS app to store and display periodic bodyweight measurements. I've got a singleton which returns a mutablearray of the shared store of measurement object. Each measurement will have at least a date and a body weight, and I want to be able to add historic measurements.
I'd like to display the measurements in date order. What's the best way to do this? As far as I can see the options are as follows: 1) when adding a measurement - I override addobject to sort the shared store every time after a measurement is added, 2) when retrieving the mutablearray I sort it, or 3) I retrieve the mutablearray in whatever order it happens to be in the shared store, then sort it when displaying the table/chart.
It's likely that the data will be retrieved more frequently than a new datum is added, so option 1 will reduce redundant sorting of the shared store - so this is the best way, yes?
You can use a modified version of (1). Instead of sorting the complete array each time a new object is inserted, you use the method described here: https://stackoverflow.com/a/8180369/1187415 to insert the new object into the array at the correct place.
Then for each insert you have only a binary search to find the correct index for the new object, and the array is always in correct order.
Since you said that the data is more frequently retrieved than new data is added, this seems to be more efficient.
If I forget your special case, this question is not so easy to answer. There are two basic solutions:
Keep array unsorted and when you try to access the element and array is not sorted, then sort it. Let's call it "lazy sorting".
Keep array sorted when inserting elements. Note this is not about appending new element at the end and then sort the whole array. This is about finding where the element should be (binary search) and place it there. Let's call it "sorted insert".
Both techniques are correct and useful and deciding which one is better depends on your use cases.
Example:
You want to insert hundreds of elements into the array, then access the elements, then again insert hundreds of elements, then access. In summary, you will be inserting values in big chunks. In this case, lazy sorting will be better.
You will often insert individual elements and you will access the elements often. Then sorted insert will have better performance.
Something in the middle (between inserting 1 and inserting tens of elements). You probably don't care which one of the methods will be used.
(Note that you can use also specialized structures to keep an array sorted, not based on NSArray, e.g. structures based on a balanced tree, while keeping number of elements in the subtree).

Retrieving object from NSMutableArray based on key value of child NSMutableDictonary

So I have an NSMutableArray in my app what is filled like so:
NSMutableArray
--Object 1 (NSMutableDictonary)
--Value (i) for key (key)
--Value (i) for key (key)
--Object 2 (NSMutableDictonary)
--Value (i) for key (key)
--Value (i) for key (key)
i need to be able to select an object from within the main NSMutableArray by looking for a key what matches a value of one of the NSMutableDictonary's keys...
I understand i could run a loop like so to achieve this:
for (NSMutableDictionary *object in arrayObject) {
if ([[object objectForKey:#"keyToSearch"] integerValue] == keyToCompare) {
return [object objectForKey:#"keyToReturn"];
}
}
However my concern is that if this array grows (what it can do) then this will take time to run a search on it..
So I was wondering is there any other way to retrieve the same results but more efficiently?
Thanks
Liam
The search is obviously going to take linear time in the number of dictionaries in the array. You're not going to get around that by using a different way to search. You could rewrite your search to use an NSPredicate, and it would be slightly shorter but it wouldn't be any faster.
If you want to make the search faster, you'll have to modify your data structure. Or, you could create a NSDictionary to serve as a lookup table, where the keys of the NSDictionary are values of keyToSearch, and the values are the NSMutableDictionaries in your array.
Still, unless your array gets really really, big the search time will be negligible, and you shouldn't worry about it.
Ultimately, any enumeration of any array will take time that grows as the size of the array grows. If you have any way to hint at the location of it, it may make it faster, but otherwise, Fast Enumeration is probably the fastest way to run through the data in the way that you want to.
Unless you run through hundreds of objects, the time taken should be negligible.

"sortedArrayHint" method of NSArray class, what is the purpose of this method and how is it used?

Question is the same as the title.
("sortedArrayHint" method of NSArray class, what is the purpose of this method and how is it used)
I read documentation but the explanation is not clear.
Please explain the purpose of this method and its usage.
The idea is simple. Assume you have a large array that should always be sorted. Changing or inserting even one element means you have to resort the array. Sorting is costly.
The method -[NSArray sortedArrayHint] can be called on an already sorted array in order to get private internal data that can be used to speed up a sort of the same array given that only a small change has been made.
Usage is simple:
Get and store the hint from the original sorted array using -[NSArray sortedArrayHint].
After a small change; resort using -[NSArray sortedArrayUsingFunction:context:hint:] with the stored hint.
After a large change; resort using -[NSArray sortedArrayUsingFunction:context:], and get a new hint.
What is a small, or large, change is something you must measure with Instruments.
I never use this myself, since I have found it more effective to use my own categories on NSArray and NSMutabelArray for sorted inserts, that uses a binary search, on sorted array. My code is available as open source here: https://github.com/Jayway/CWFoundation

Order Integers In Ascending and Descending Orders

I'm working with Objective-C, but probably it doesn't matter the programming language for this. So basically I have an array, with say, the integers 12, 5, and 17, and I want to be able to pull out the largest number, or the smallest, or second smallest, etc.
Basically I want to be able to sort them into ascending or decending order so I could pick out, for instance, the second smallest number by retrieving the objectAtIndex: 1 if it is sorted in ascending order. I feel like this is incredibly obvious but I can't think of how to do it at the moment, so I would love it if someone could enlighten me.
If you have an NSArray with NSNumber instances, then the sort you are looking for is as easy as this:
NSArray* sortedNumbers = [unorderedNumbers sortedArrayUsingSelector:#selector(intValue)];
It will sort ascending, so [sortedNumbers lastObject] will be the greatest value.
There are many more sorting methods on NSArray if you have more specific needs. NSArray sorting
Almost every high level language, including objective-c, have library to sort an array. But as you said that language does not matter, probably you are looking for the algorithm itself. There are a number a sorting algorithms with different computational complexity. You can find them in any standard algorithm book. Or these 2 pages might be helpful:
Sorting Algorithms in Wikipedia.
sorting-algorithms.com. Contains nice explanation with animation.
And if you are interested particularly in objective-c, check the Sorting section of NSArray reference. This contains an example to sort an array of integer.
Just sort the array in ascending order (I don't use objective C, but I am sure there is a function for it) and then get the element wherever you want...
To get the largest
array[array.length - 1]
Second largest
array[array.length -2]
Smallest
array[0]
Second smallest
array[1]
You should check to make sure that the array index is valid:
if (array.length - 2> 0) //Second largest element
return array[array.length - 2];
Or:
if (array.length > 1) //Second smallest element
return array[1];
See here for how to sort an array in objective C:
http://howtomakeiphoneapps.com/2009/03/how-to-sort-an-array-in-objective-c/
If you want to preserve the order of the original array, one method is to create a second array that just contains the numbers 0, 1, ... n, representing indexes into the first array. Then sort the second array, but instead of comparing its values, compare the corresponding values that it points to in the first array. (You could also just store pointers and sort based on the dereferenced pointers.)
Then to find the second-largest number, look up the index in the second-to-last position in the second array and see where it points to in the first array.
If you want to get fancy and avoid sorting, this lecture describes an algorithm for finding the k-largest element in linear time. I haven't actually used it, but it looks like it might be a good method if your data changes often, as you wouldn't have to maintain the extra array.
If your goal is to get the highest number, or lowest, or second-lowest, or what have you, and you only need one number from the result, then sorting is overkill. Instead you should just iterate over the entire array and keep track of the highest (or lowest, or 2 lowest (for the second-lowest)) number seen so far. If your language supports this, it'll be called a "fold". The only reason to actually sort the array is if you need to access multiple different ranked values from the array.

How to return objects in an NSArray at specified indexes?

Example:
I have an NSArray with 40 objects. What is the most efficient way to return ONLY those objects with index equal to a number specified in another NSArray (e.g {0, 27, 36} for example)?
Can a predicate be used here? Or is there a more simple and efficient approach?
Why don't you just iterate over the index array and look up each index in the data array replacing the index with the looked-up object.
In the end, the array that held the indices now holds the objects. If you don't want to wipe out your index array, then just create a new array of the same size as the index array and put the objects there.
You might be over-thinking the design of this and falling prey to micro-optimization. (Which is a bad thing.)
There is a method (objectsAtIndexes) for returning specified indexes from an original array, but it requires an NSIndexSet as its argument, and there isn't a built-in way to convert your array of indices to an index set. On the plus side, you can generate the index set with a short loop, as follows:
NSMutableIndexSet indexes = [NSMutableIndexSet indexSet];
for (NSNumber * number in indexArray)
{
[indexes addIndex:[number intValue]];
}
return [originalArray objectsAtIndexes:indexes];
Is this any more efficient than simply looping through the original array? I have no idea. You would have to profile your app to be sure.
I remember reading one time, and I cant say where but it stuck in my mind, that if this was something you need to do many times and the array is fairly large that there is a more efficient way. You could create a new dictionary from that array where each entry has the key of the index number and the value is the array item. You only create the dictionary once so the hard work is over in one shot. Then every time you need to access values at certain indexes you just ask for valueForKey:#"indexNumber". But I never had a need for this so I never tested if it was more efficient in the long run... it's just a thought.