Objective C: Sort Two Dimensional Array - ios

I have an array of arrays. The contained array's first elements are all NSDate objects. I would like to sort the array containing the arrays in order from most recent to least. For some reason, the below sorting algorithm results in an infinite loop. Can anyone help me out? Thank you.
Best...SL
//array is the array containing all of the other arrays(that have NSDates as their first elements)
//temp is the new array being added to the end of the array, to later be sorted into the correct position.
[array addObject:temp];
NSMutableArray *tempArray;
for (int i=0; i<[array count]; i++)
{
NSDate *session1, *session2;
session1 = [[array objectAtIndex:i] objectAtIndex:0];
session2 = [[array objectAtIndex:[array count]-1] objectAtIndex:0];
if([session1 compare:session2] == NSOrderedDescending)
{
tempArray = [array objectAtIndex:i];
[array insertObject:[array objectAtIndex:[array count]-1] atIndex:i];
[array insertObject:tempArray atIndex:[array count]-1];
}
}

This results in an infinite loop because, in every step, you're inserting two more values into the array. Thus your array is growing faster than you are traversing it. I'm assuming you meant to swap the values.
In any case, a much simpler and more efficient sort is to use the built-in sorting capabilities:
// NSArray *sortedArray, with the unsorted 'array' pulled from some other instance
sortedArray = [array sortedArrayUsingComparator:^(id a, id b) {
return [[b objectAtIndex:0] compare:[a objectAtIndex:0]];
}];

If array is mutable and you want to sort it in place:
[array sortUsingComparator:^(id a, id b) {
return [b[0] compare:a[0]];
}];
If array is immutable or you want to leave it alone and make a sorted copy:
NSArray *sortedArray = [array sortedArrayUsingComparator:^(id a, id b) {
return [b[0] compare:a[0]];
}];

Related

how to do shift and push operation in objective c

I have an array [1,2,3,4]
I need to continously shift and push one element into the same array
so that the first variable values will be 1,2,3,4,1,2,3,4,...
and second variable values will be 2,3,4,1,2,3,4,1,...
How to do that??
Use NSMutableArray like:
1) to get the object at the first position:
object = [nameArray firstObject];
[nameArray removeObjectAtIndex:0];
2) then insert it in last position:
[nameArray addObject:object];
p.s. remember to always add some sanity checks.
You would need
- exchangeObjectAtIndex:withObjectAtIndex:
Exchanges the objects in the array at given indices.
See Documentation here
Example
NSMutableArray *array = [NSMutableArray array];
[array setArray:#[#"Eezy",#"Tutorials",#"Website"]];
[array exchangeObjectAtIndex:0 withObjectAtIndex:2];
NSLog(#"%#",array);
NSMutableArray *obj = [NSMutableArray arrayWithObjects:#"1",#"2",#"3",nil];
[obj exchangeObjectAtIndex:0 withObjectAtIndex:obj.count - 1];
NSLog(#"%#",obj);

Compare NSMutableArray elements to find second largest from list

I'm trying to find the second largest number in an array. Why is this code not working?
NSMutableArray *array1=[[NSMutableArray alloc]initWithObjects:#5,#25,#48,#2,#52,#53, nil];
id temp,larg2;int k=0;
while(k<2)
{
for(int j=0;j<5-k;j++)
{
if( [array1 objectAtIndex:j]>[array1 objectAtIndex:j+1])
{
temp=[array1 objectAtIndex:j];
[array1 replaceObjectAtIndex:j withObject:[array1 objectAtIndex:j+1]];
[array1 replaceObjectAtIndex:j+1 withObject:temp];
if(k==1 && j==3). //this statement is not running??
{ larg2=temp;
NSLog(#"The answer is %#",larg2);
}
}
}
k++;
}
NSLog(#"The value of Second Largest Element is %#",larg2);
}
How do I find the second largest element?
There is no need to sort the array if all you need is the 2nd largest item, and the sort algorithm you're using is very poor (It has O(n^2) performance, which means it will get slower with the square of the number of items, so that with just a few hundred items it will start to take a long time to complete, and with a few thousand items it will seem to hang.)
Thus there's no real point in trying to debug your code. It's "putting lipstick on a pig" as the expression goes.
Instead of sorting the array, do a single pass through the array. Set a variable largest and secondLargest. If the current array entry is bigger than largest, check to see if largest is bigger than secondLargest, and replace secondLargest, then replace largest With the new largest value. That will give you O(n) performance (time to completion goes up linearly with the number of items in the array) which is faster than the fastest sort algorithms, and also a lot simpler to implement.
If you don't care about performance, just use a system sort method, then take the 2nd to last item in the sorted array. The system's sort functions are optimized, and typically have O(n log n) performance, which is quite good for sort algorithms.
First create a NSSet before if you need to exclude duplicates then Sort the array descending, pick the second element.
NSArray * unsortedArray = #[#22,#11,#53,#15,#7,#37,#11,#92,#84,#5];
NSSet *numberSet = [NSSet setWithArray: unsortedArray];
NSArray *sortedNumbers = [[numberSet allObjects] sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"self" ascending:NO] ]];
NSNumber *secondHighest;
if ([sortedNumbers count] > 1){
secondHighest = sortedNumbers[1];
}
NSLog(#"%ld", secondHighest);
Without sorting :
NSInteger max1 = -1, max2 = -1;
for (NSInteger i = 1; i < [unsortedArray count]; ++i) {
if ([unsortedArray[i] integerValue] > max1) {
max2 = max1;
max1 = [unsortedArray[i] integerValue];
} else if ([unsortedArray[i] integerValue] > max2 && [unsortedArra1y[i] integerValue] < max1) {
max2 = [unsortedArray[i] integerValue];
}
}
NSLog(#"%ld %ld",max1, max2);
If you have small set of array then you can use sorting method to sort an array but for the large number of element it will take more time with increase in numbers with very poor in performance O(n^2) and second method is simple and performance O(n).
Try this one
NSArray *arr = [[NSArray alloc]initWithObjects:#20,#12,#24, nil];
NSSet *tempSet = [NSSet setWithArray: arr];
NSArray *arr1 = [[tempSet allObjects] sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"self" ascending:YES] ]];
NSLog(#"%#",[arr1 objectAtIndex:1]);

Looping thru NSArray of NSString logic

I need help with the following:
I have an NSArray with NSStrings, I want to loop thru these strings and find a matching string, when match is found the strings after this match will be extracted into an NSDictionary until a certain other match is hit.
Here is an example:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
So I want to loop thru this array and split it in 2 arrays one for fruit and one for vegetable.
Anyone can help with the logic?
Thanks
This is probably the simplest way to solve the problem:
NSArray *array = #[#"Chair",#"Fruit",#"Apple",#"Orange",#"Vegetable",#"Tomato",#"Fruit",#"Banana",#"Vegetable",#"Cucumber"];
NSMutableArray *fruitArray = [NSMutableArray array];
NSMutableArray *vegetableArray = [NSMutableArray array];
NSMutableArray *currentTarget = nil;
for (NSString *item in array)
{
if ([item isEqualToString: #"Fruit"])
{
currentTarget = fruitArray;
}
else if ([item isEqualToString: #"Vegetable"])
{
currentTarget = vegetableArray;
}
else
{
[currentTarget addObject: item];
}
}
In one iteration over the array, you just keep adding items to a result array using a pointer to one of two result arrays according to the last occurrence of the #"Fruit" or #"Vegetable" string.
This algorithm ignores all items before the first occurrence of the #"Fruit" or #"Vegetable" string, because the currentTarget is initialized to nil, which ignores the addObject: messages. If you want different behaviour, just change the initialization.
You said you wanted the results in a NSDictionary, but didn't specify what should be the key. If you want one NSDictionary with two keys, Fruit and Vegetable, and values NSArrays containing the items, just use the arrays previously created:
NSDictionary *dict = #{ #"Fruit": fruitArray, #"Vegetable": vegetableArray };
PS: You have a typo in your example, Vegtable instead of Vegetable. I corrected it in my code, so keep it in mind.
If I completely understand you:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
NSMutableArray *fruits = [NSMutableArray array];
NSMutableArray *vegtables = [NSMutableArray array];
for (NSInteger i = 0; i < array.count; ++i){
if ([array[i] isEqualToString:#"Fruit"]){
++i;
[fruits addObject:array[i]];
}
else if ([array[i] isEqualToString:#"Vegtable"]){
++i;
[vegtables addObject:array[i]];
}
}

Finding a duplicate numbers in an array and then counting the number of duplicates

How would I take an array with long list of numbers that contains duplicates, so for instance:
NSArray *array = [NSArray arrayWithObjects:#"45", #"60", #"100",#"100", #"100", #"60"nil];
Just imagine that this is a HUGE list of random numbers. Now I'm sure that I have to use something like NSSet for this, but i'm not sure how to execute this. Also, once we identify the duplicates I'm guessing that I would then add those numbers to an array, and then call
[array count];
Any ideas?
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:array];
int duplicates = 0;
for (id object in set) {
if ([set countForObject:object] > 1) {
duplicates++;
}
}
This will calculate how many elements have a duplicate.
A sidenote, that array contains a bunch of strings, no numbers...
Anyway, if the goal is to get just the count you could use the following single line to get it.
NSUInteger diff = [array count] - [[array valueForKeyPath:#"#distinctUnionOfObjects.self"] count];
This uses KVC (Key-Value Coding) to get all distinct objects (that is ones without a dupe) counts them and gets the difference from the original count.
NSCountedSet is perfect for what you want to do.
NSArray *array = [NSArray arrayWithObjects:#"45", #"60", #"100",#"100", #"100", #"60",nil];
NSCountedSet *countedSet = [NSCountedSet setWithArray:array];
__block NSUInteger totalNumberOfDuplicates = 0;
[countedSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
NSUInteger duplicateCountForObject = [countedSet countForObject:obj];
if (duplicateCountForObject > 1)
totalNumberOfDuplicates += duplicateCountForObject;
NSLog(#"%# appears %ld times", obj, duplicateCountForObject);
}];
NSLog(#"Total number of duplicates is %ld", totalNumberOfDuplicates);
produces:
45 appears 1 times
60 appears 2 times
100 appears 3 times
Total number of duplicates is 5
Use filteredArrayUsingPredicate this use a predicate with your condition and return an array with the objects you need.
NSArray* arr=[[NSArray alloc] initWithObjects:#"10",#"11",#"10",#"2", nil];
NSLog(#"%d",[[arr filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF == '2'"]] count]);

Sort NSArray of NSStrings based on a super set of ordered Strings

I have an NSArray which contains some NSString objects. For example:
NSArray *objects = #[#"Stin",#"Foo",#"Ray",#"Space"];
Now I need to sort this array based on following order of Strings.
NSArray *sortOrder = #[#"John",#"Foo",#"Space",#"Star",#"Ray",#"Stin"];
So the answer should be
NSArray *sorted = #[#"Foo",#"Space",#"Ray",#"Stin"];
How can I achieve this?
ANSWER:
Based on Accepted answer of dasblinkenlight, I did following and it worked to charm.
NSMutableArray *objects = #[#"Star",#"Stin",#"Foo",#"Ray",#"Space",#"John"];
NSArray *sortOrder = #[#"John",#"Foo",#"Space",#"Star",#"Ray",#"Stin"];
[objects sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
int index1 = [sortOrder indexOfObject:obj1];
int index2 = [sortOrder indexOfObject:obj2];
if (index1 > index2)
return NSOrderedDescending;
if (index1 < index2)
return NSOrderedAscending;
return NSOrderedSame;
}];
Create NSComparator that holds a reference to the superset array, and decides the relative order of strings by comparing the results of calling [superset indexOfObject:str] on both strings. Call sortedArrayUsingComparator: passing an instance of NSComparator to get the desired ordering.
dasblinkenlight's solution would work, but like most programming problems there are multiple ways to go about it. Here is one such alternative:
NSMutableArray *sorted = [NSMutableArray arrayWithCapacity:0];
[sortOrder enumerateObjectsUsingBlock:^(NSString *sortedString, NSUInteger idx, BOOL *stop) {
if ([objects containsObject:sortedString]) {
[sorted addObject:sortedString];
}
}];
The variable names correspond to the variable names used in the original question.
This works because the enumeration happens in order. Therefore, what takes place is, essentially, a cull of the objects that exist in both arrays in the order as specified by sortOrder.

Resources