Fastest way to compare/set strings - iphone

I have an array of Place objects. Each Place object has a name and code property, both strings. Each Place object already has a code, but I need to look up the name property from a server. I get back 2 arrays: one contains name, the other codes. These arrays are ordered so that the name at some index in the nameArray corresponds exactly with the code at the same index of the codeArray.
I have been looping through the array of Place objects, then checking to see if the code property for that Place is the same as the current index in the codeArray. If it is, I set the name of that Place by using the same index in the nameArray:
for(int i = 0; i < [placesArray count]; i++)
{
for(int j = 0; j < [codeArray count]; j++) {
if([[[placesArray objectAtIndex:i] code] isEqualToString:[codeArray objectAtIndex:j]]) {
[[placesArray objectAtIndex:i] setName:[nameArray objectAtIndex:j]];
}
}
}
This works but isn't terribly fast - it can take 30 seconds with 1000+ Places to loop through.
Is there a faster way?

As with anytime you're trying to optimize performance, you should profile the code using Instruments to find out where the bottleneck actually is. That said, looping through the placesArray for each name in the nameArray and doing a string comparison is pretty inefficient.
How about something like this?
NSMutableDictionary *placesByCode = [NSMutableDictionary dictionaryWithCapacity:[placesArray count]];
for (Place *aPlace in placesArray) {
[dictionary setObject:aPlace forKey:aPlace.code];
}
NSMutableDictionary *namesByCode = [NSMutableDictionary dictionaryWithCapacity:[namesArray count]];
for (int i=0; i<[namesArray count]; i++) {
NSString *name = [namesArray objectAtIndex:i];
NSString *code = [codeArray objectAtIndex:i];
[namesByCode setObject:name forKey:code];
}
for (NSString *code in namesByCode) {
Place *place = [placesByCode objectForKey:code];
place.name = [namesByCode objectForKey:namesByCode];
}
Looking up each place by its code in the dictionary should be quite a bit faster than manually looping through the whole place array for each name.

You can use for NSArray -containsObject
if ([myarray containsObject:myObject]) {
// ...
}

Try using a break statement in the inner loop. This way you don't need to loop through the entire loop each time.
for(int i = 0; i < [placesArray count]; i++)
{
for(int j = 0; j < [codeArray count]; j++) {
if([[[placesArray objectAtIndex:i] code] isEqualToString:[codeArray objectAtIndex:j]]) {
[[placesArray objectAtIndex:i] setName:[nameArray objectAtIndex:j]];
break;
}
}
}
You could also make the second array become smaller as you find more results. It will cost you more memory but 1000 strings isn't much anyway.
NSMutableArray * tempCodeArray = [NSMutableArray arrayWithArray:codeArray];
for(int i = 0; i < [placesArray count]; i++)
{
for(int j = 0; j < [tempCodeArray count]; j++) {
if([[[placesArray objectAtIndex:i] code] isEqualToString:[tempCodeArray objectAtIndex:j]]) {
[[placesArray objectAtIndex:i] setName:[nameArray objectAtIndex:j]];
[tempCodeArray removeObjectAtIndex:j];
break;
}
}
}

The problem was not the counting for the array, it's the embedded for loop which will take O(n*n) and in Andrew's solution, it's only O(n)+O(n)+O(n)+whatever take to find a object of the key in the dictionary, which i guess would be in a hash table lookup and that's really fast.
Colby, you probably will be ok with Andrew's solution. If you still wanna improve the performance, then a good idea would be sort the array's first then do lookup.
Hope this helps.

Related

How to store objects of a mutable Array into another mutable array in form of arrays.?

I have an NSMutable array which contains some objects and I want to store these objects into a different Mutable array in the form of different arrays.
For ex: I have an array named sessionArrayType4 which has these objects.
"New Attendee Reception",
"Attendee Reception",
"Banquett",
"Tour and BBQ"
And I want to store in another Mutable array named globalSessionArray and I'm expecting result something like below.
(("New Attendee Reception"), ("Attendee Reception"), (Banquett), (Tour and BBQ))
Here is my code:
if(self.pickerSelectedRow == [self.typePickerArray objectAtIndex:3])
{
for (int i =0; i< [self.sessionArrayType4 count]; i++)
{
if(self.displayTime == [[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"start_time"])
{
[self.sessionRowArray addObject:[[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"session_name"]];
self.rowCount = self.rowCount + 1;
}
else
{
[self.sessionRowArray removeAllObjects];
self.displayTime = [[self.sessionArrayType4 objectAtIndex:i] valueForKey:#"start_time"];
[self.sessionRowArray addObject:[[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"session_name"]];
[self.globalSessionArray addObject:self.sessionRowArray];
}
}
}
But I am getting output something like this:
((Tour and BBQ), (Tour and BBQ), (Tour and BBQ), (Tour and BBQ))
You're going to have to alloc/init your values into an object for each iteration of the for loop or else it will continually stick in memory and overwrite itself.
if(self.pickerSelectedRow == [self.typePickerArray objectAtIndex:3])
{
NSArray *
for (int i =0; i< [self.sessionArrayType4 count]; i++)
{
NSObject *myNewObject = [[NSObject alloc] init];
if(self.displayTime == [[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"start_time"])
{
myNewObject = [[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"session_name"];
[self.sessionRowArray addObject: myNewObject];
self.rowCount = self.rowCount + 1;
}
else
{
[self.sessionRowArray removeAllObjects];
//NSLog(#"%#",self.sessionRowArray);
self.displayTime = [[self.sessionArrayType4 objectAtIndex:i] valueForKey:#"start_time"];
myNewObject = [[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"session_name"]];
[self.sessionRowArray addObject:myNewObject];
// NSLog(#"%#",self.sessionRowArray);
[self.globalSessionArray addObject:self.sessionRowArray];
// NSLog(#"%#",self.globalSessionArray);
}
}
}
You need to allocate an temp array in for loop to get a final array of arrays.
The code is very confusing but you can modify like below to get correct result:
if(self.pickerSelectedRow == [self.typePickerArray objectAtIndex:3])
{
for (int i =0; i< [self.sessionArrayType4 count]; i++)
{
if(self.displayTime == [[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"start_time"])
{
[self.sessionRowArray addObject:[[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"session_name"]];
self.rowCount = self.rowCount + 1;
}
else
{
[self.sessionRowArray removeAllObjects];
NSMutableArray* tempArray = [[NSMutableArray alloc] init];
//NSLog(#"%#",self.sessionRowArray);
self.displayTime = [[self.sessionArrayType4 objectAtIndex:i] valueForKey:#"start_time"];
[tempArray addObject:[[self.sessionArrayType4 objectAtIndex:i]valueForKey:#"session_name"]];
// NSLog(#"%#",self.sessionRowArray);
[self.globalSessionArray addObject:tempArray];
// NSLog(#"%#",self.globalSessionArray);
}
1)
if(self.pickerSelectedRow == [self.typePickerArray objectAtIndex:3])
This expression and similar ones look like incorrect, because the left value look likes int or NSInteger and right value is NSObject. If they are both NSObjects then use isEqual instead.
2)
sessionArrayType4
it is correct, but no serious programmer uses such names for variables.
3)It is hard to understand what do you want because of incomplete code and a lot of NSLog calls. You have also added JSON code which is particularly incompatible with a previous part of code.
So edit your code first

Error when trying to shuffle an NSMutableArray

I'm trying to shuffle an NSMutableArray so that its order will be mixed up every-time someone loads the view.
In my -(void)viewDidLoad I'm putting the following code (as suggested by other users):
NSMutableArray *shuffleTwo = [self.chosenTeamDict objectForKey:#"clubs"];
int random = arc4random() % [shuffleTwo count];
for (int i = 0; i < [shuffleTwo count]; i++) {
[shuffleTwo exchangeObjectAtIndex:random withObjectAtIndex:i];
}
NSLog(#"%#", shuffleTwo);
But when I do this and try and run the page, I get the following error:
2012-07-09 18:42:16.126 Kit-Quiz[6505:907] (null)
libc++abi.dylib: terminate called throwing an exception
Can anyone advice either a new way of shuffling this array, or advice me on how to avoid this error..!? I'm building for iOS 5 and I'm using Xcode45-DP1. Thanks in advance!
(EDIT)
I've also tried this method and I get the same error:
NSMutableArray *shuffledArray = [[NSMutableArray alloc] init];
NSMutableArray *standardArray = [self.chosenTeamDict objectForKey:#"clubs"];
for(int s = 0; s < [standardArray count]; s++){
int random = arc4random() % s;
[shuffledArray addObject:[standardArray objectAtIndex:random]];
}
NSLog(#"%#", shuffledArray);
NSMutableArray *standardArray = [self.chosenTeamDict objectForKey:#"clubs"];
int length = 10; // int length = [yourArray count];
NSMutableArray *indexes = [[NSMutableArray alloc] initWithCapacity:length];
for (int i=0; i<10; i++) [indexes addObject:[shuffledArray objectAtIndex:i]];
NSMutableArray *shuffle = [[NSMutableArray alloc] initWithCapacity:length];
while ([indexes count])
{
int index = rand()%[indexes count];
[shuffle addObject:[indexes objectAtIndex:index]];
[indexes removeObjectAtIndex:index];
}
for (int i=0; i<[shuffle count]; i++) NSLog(#"%#", [shuffle objectAtIndex:i]);
NSLog(#"%#", shuffle);
^^ ANSWER
Try Fisher-Yates shuffle. It goes like this:
int count = shuffledArray.count;
for(int i=count; i>0; i--) {
int j = arc4random_uniform(count);
[shuffledArray exchangeObjectAtIndex:j withObjectAtIndex:i];
}
make sure that your array is non-nil and all the entries are allocated objects :)
Source: Fisher-Yates Shuffle
First, you really should enable exception breakpoints. In XCode on the left-hand panel, click the breakpoint tab, click the "+" sign at the bottom-left -> exception breakpoint -> done.
I suspect your problem lies here:
int random = arc4random() % [shuffleTwo count];
If [shuffleTwo count] evaluates to zero (also if shuffleTwo is nil) it will throw a division by zero exception. Edit: Doesn't seem to be the case in Objective-C.

Loading values into an array from two different arrays iphone sdk

Here I am having a situation, I'm using the following code:
int x=0;
for (int i=0; i<=[arrayDeals count]-1; i++) {
x++;
//NSString *deal = [arrayDeals objectAtIndex:i];
combinedArr = [[NSMutableArray alloc]initWithObjects:
[CustomObject customObjectWithName:[arrayDeals objectAtIndex:i] andNumber:x],nil];
}
I need to load the values from arrayDeals and the 'x' value into combinedArr. So, I put this in a for loop. But i got only one value from each arrays. What is went wrong here? Please help me. (here CustomObject is a NSObject)
Thank you.
Well there are many things wrong with the code you posted, but I think this is what you want:
int x = 0;
NSMutableArray *combinedArr = [[NSMutableArray alloc] init]:
NSInteger count = [arrayDeals count];
for (int i = 0; i < count; i++) {
x++;
CustomObject *customObject = [CustomObject customObjectWithName:[arrayDeals objectAtIndex:i] andNumber:x];
[combinedArr addObject:customObject];
}
To give you some idea of what is wrong with the code you posted:
combinedArr = [[NSMutableArray alloc]initWithObjects:
[CustomObject customObjectWithName:[arrayDeals objectAtIndex:i] andNumber:x],nil];
Here you create a new NSMutableArray to which you assign an new object to taked the object from the array arrayDeals. But you create this NSMutableArray for every item in the array arrayDeals and you assign them to the same variable.
So each iteration you leak the NSMutableArray.
Also :
for (int i=0; i<=[arrayDeals count]-1; i++) {
is the same as
for (int i=0; i < [arrayDeals count]; i++) {
but the count is called every time you iterate, so as per my example I saved the count in a int to just speed things up.
You could even speed the code up using fast Enumeration:
NSInteger x = 0;
NSMutableArray *combinedArr = [[NSMutableArray alloc] init]:
for (id object in arrayDeals) {
id secondObject = [secondArray itemAtIndex:x];
// Arrays start at 0 so only up it after we've got the object.
x++;
CustomObject *customObject = [CustomObject customObjectWithName:object andNumber:x];
[combinedArr addObject:customObject];
}

for loop in objective c

Can someone help take a look at this method and advise please.. SOmethings seems not quite right.
for(int i = 0; i<sizeof(_annotation2) - 5 ; i++){
[a.annotationsPatients addObject:[_annotation2 objectAtIndex:i]];
}
You cannot use sizeof() to get the number of elements in an NSArray. You use count.
for(int i = 0; i<[_annotation2 count] - 5 ; i++){
[a.annotationsPatients addObject:[_annotation2 objectAtIndex:i]];
}
You're using sizeof incorrectly. sizeof gets the size of a given data type, not the length of what I assume is an NSArray. To get the length of an NSArray, use the count method, like so:
NSUInteger arrayLength = [someArray count];
for (int x = 0; x < arrayLength; ++x)
{
// do whatever in here
}
Actually "count" method is used instead of "sizeof".
Review your code as below:
for(int i = 0; i<[_annotation2 count] - 5 ; i++){
[a.annotationsPatients addObject:[_annotation2 objectAtIndex:i]];
}

How to get index of an item in an array

I am having array called stored and I want to access their indexes so that I can select them individually to do my operations.
If I want to print their indexes, what should I do?
use NSArray's indexOfObject: method. Such as the following:
NSUInteger fooIndex = [someArray indexOfObject: someObject];
int totalElements = [anArray count];
for(int i=0; i < totalElements; i++)
{
data = [myArray indexOfObject:i];
}
The above code will give you the data if you pass in the index
NSString *haystackText = #"Hello World";
int totalElements = [anArray count];
for(int i=0; i < totalElements; i++)
{
BOOL result = [haystackText caseInsensitiveCompare:[myArray objectAtIndex:i] == NSOrderedSame;
if(result)
{
NSUInteger fooIndex = [myArray indexOfObject: haystackText];
return fooIndex;
}
}
The code above will first find the element in the array and if it exists then return the index.
[array indexOfObject:object]
returns index of "object"
You can use indexOfObject method to get the index of element.
for example
This will give you index of your object
NSInteger index = [yourArray indexOfObject:objectName];
This worked for me. Hope this helps.
You can get a list of the indexes by using the count method which returns the number of elements in the array:
int numElements = [myArray count];
I'll leave it as an exercise to print out the actual index values :)
This article has some great examples of how to iterate over an array. Then, inside the loop, you can use NSLog to print the index.