Modify Object while Iterating over a NSMutableArray - objective-c

I was trying to modify an object from an array while iterating over it and couldn't find a nice way of doing it... This is what I've done, is there a simpler way of doing this? I've been googling for while but I couldn't find anything...
NSMutableArray *tempArray = [[NSMutableArray alloc]init];
NSArray *days = [restaurant.hours componentsSeparatedByString:#","];
for (NSString *day in days) {
NSString *dayWithOutSpace = [day stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[tempArray addObject:dayWithOutSpace];
}
days = [NSArray arrayWithArray:tempArray];
Thanks!

As suggested by others there might be better ways to accomplish the exact task in the question, but as a general pattern there is nothing wrong with your approach - build a new array.
However if you need to modify a mutable array, say because multiple objects reference it, there is nothing wrong with that either - that is why it is mutable after all! You just need to use standard iteration rather than enumeration - the latter is just the wrong tool for the job. E.g.:
NSMutableArray *anArray = ...
NSUInteger itemCount = [anArray count];
for(NSUInteger ix = 0; ix < itemCount; ix++)
{
// read from anArray[ix] and store into anArray[ix] as required
}

The way you do it is OK, since you are not modifying the array you are looping through.
Here is another way, a little less intuitive and probably not faster:
NSArray* days = [[[restaurant.hours componentsSeparatedByString:#" "] componentsJoinedByString:#""] componentsSeparatedByString:#","];

Considering your hours string is like: 2, 5, 6, 7 etc. you can use the string as #", " directly.
NSArray *days = [restaurant.hours componentsSeparatedByString:#", "];

Maybe it is better to eliminate all white spaces before separation.
NSString *daysWithOutSpaces = [restaurant.hours stringByReplacingOccurrencesOfString:#"[\\s\\n]" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, restaurant.hours.length)];
NSArray *days = [daysWithOutSpaces componentsSeparatedByString:#","];

Related

Take all numbers separated by spaces from a string and place in an array

I have a NSString formatted like this:
"Hello world 12 looking for some 56"
I want to find all instances of numbers separated by whitespace and place them in an NSArray. I dont want to remove the numbers though.
Whats the best way of achieving this?
This is a solution using regular expression as suggested in the comment.
NSString *string = #"Hello world 12 looking for some 56";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:#"\\b\\d+" options:nil error:nil];
NSArray *matches = [expression matchesInString:string options:nil range:(NSMakeRange(0, string.length))];
NSMutableArray *result = [[NSMutableArray alloc] init];
for (NSTextCheckingResult *match in matches) {
[result addObject:[string substringWithRange:match.range]];
}
NSLog(#"%#", result);
First make an array using NSString's componentsSeparatedByString method and take reference to this SO question. Then iterate the array and refer to this SO question to check if an array element is number: Checking if NSString is Integer.
I don't know where you are looking to do perform this action because it may not be fast (such as if it's being called in a table cell it may be choppy) based upon the string size.
Code:
+ (NSArray *)getNumbersFromString:(NSString *)str {
NSMutableArray *retVal = [NSMutableArray array];
NSCharacterSet *numericSet = [NSCharacterSet decimalDigitCharacterSet];
NSString *placeholder = #"";
unichar currentChar;
for (int i = [str length] - 1; i >= 0; i--) {
currentChar = [str characterAtIndex:i];
if ([numericSet characterIsMember:currentChar]) {
placeholder = [placeholder stringByAppendingString:
[NSString stringWithCharacters:&currentChar
length:[placeholder length]+1];
} else {
if ([placeholder length] > 0) [retVal addObject:[placeholder intValue]];
else placeholder = #"";
return [retVal copy];
}
To explain what is happening above, essentially I am,
going through every character until I find a number
adding that number including any numbers after to a string
once it finds a number it adds it to an array
Hope this helps please ask for clarification if needed

Neater way to write all these parameters

I have a bunch of saved nsuserdefault parameters that need to be written (20 cars to be exact). I am wondering what will be the neatest way to write this. I number it in order because I believe the for loop will be appropriate(not too sure). The code below represents a snippet of what I am trying to do.
NSString *emailBody=[NSString
stringWithFormat:#"%#, %#, %#",[[NSUserDefaults
standardUserDefaults]stringForKey:#"Car1"],[[NSUserDefaults
standardUserDefaults]stringForKey:#"Car2"],[[NSUserDefaults
standardUserDefaults]stringForKey:#"Car3"]];
There's no reason to save 20 separate items. Just put them in an array and store the array with setObject:forKey:. You can then fetch them all back as an array using stringArrayForKey: (or arrayForKey: or even just objectForKey:).
Once you have an array, creating a comma-separated list is very easy:
NSString *emailBody = [array componentsJoinedByString:#", "];
If you must store them as 20 items for compatibility, I would still pull them out of NSUserDefaults and put them in an array before actually using them.
Just use a for loop, something like this.
NSMutableArray *a = [NSMutableArray array];
for (int i=1;i<21;i++)
{
[a addObject:[NSString stringWithFormat:#"Car%d", i]];
}
Then just put the array into a string.
Slightly neater:
NSMutableString *emailBody = [[NSMutableString alloc] init];
for (unsigned i = 1; i <= 20; i++) {
if (i > 1)
[emailBody appendString:#", "];
[emailBody appendString:[[NSUserDefaults standardUserDefaults]
stringForKey:[StringWithFormat:#"Car%d", i]]];
}

Check if NSString exists in custom object in NSArray

I have an NSArray with Store objects. Each Store object has two NSString objects; StoreID and Name.
I would like to check quickly if an ID exists in this NSArray with Store objects.
Example:
Store *s1 = [[Store alloc] init];
s1.name = #"Some Name";
s1.id = #"123ABC";
Store *s2 = [[Store alloc] init];
s2.name = #"Some Other Name";
s2.id = #"ABC123";
NSArray *array = [[NSArray alloc] initWithObjects:s1, s2, nil];
NSString *myIdOne = #"ABCDEF";
NSString *myIdTwo = #"123ABC";
BOOL myIdOneExists = ...?
BOOL myIdTwoExists = ...?
Its the ...? I need to figure out. I know I can do this using a for loop and break when found... but this seems to me like an nasty approach since the NSArray could contain thousands of objects,... theoretically.
So I would like to know about a better solution.
Here's the thing: No matter what solution you go with, it will more or less boil down to "loop over the array and return whether or not the object was found." There is no way to search an array more quickly than this unless very specific conditions are met (e.g. the array is already sorted by the value you're searching). You can use a predicate, you can use an enumerator, you can use fast enumeration or you can use a test block — under the hood, they all amount to "loop over the array and perform a test." That's just how arrays work.
If this is something you need to do often and performance is a problem with the naive solution, a sensible solution might be to cache your IDs in an NSSet. Sets are tuned for fast member detection, so you should be able to get your answer much more quickly than you could with an array.
My personal "loop-over-the-array" solution:
BOOL idExists = NSNotFound != [stores indexOfObjectPassingTest:^(Store *store, NSUInteger idx, BOOL *stop) {
return [store.id isEqualToString:#"whatever"];
}];
(Written in the browser, so, y'know, caveat compilor.)
Try this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == %#",#"id", myID];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
if (filteredArray.count > 0)
Store *store = [filteredArray objectAtIndex:0];
Simplest solution, just use KVC:
NSArray *results = [array valueForKey:#"id"];
BOOL myIdOneExists = [results containsObject:myIdOne];
BOOL myIdTwoExists = [results containsObject:myIdTwo];
-(BOOL) id:(NSString*) theId existsInArray:(NSArray*) theArray {
for (Store* theStore in theArray) {
if ([theStore.id isEqualToString theId]) {
return YES;
}
}
return NO;
}
Another approach is to implement the isEqual method in Store to compare IDs only. Then construct a dummy Store object with the ID you're looking for and use indexOfObject or containsObject, referencing your dummy Store object.

Grabbing a specific element of an array in Objective-C

I'm splitting a string by ';', but want to specifically grab the first and second element.
I know with PHP it's just simply $array[0], just can't find anything for this for Objective-C
NSArray *tempArray = [returnString componentsSeparatedByString:#";"];
So here I have assigned my array, how can I go about getting the first and second element?
Its just simply [array objectAtIndex:0] in Objective-C ;-)
Starting with XCode 4.5 (and Clang 3.3), you may use Objective-C Literals:
NSString *tmpString1 = tempArray[1];
NSString *tmpString = [tempArray objectAtIndex:0];
NSLog(#"String at index 0 = %#", tmpString);
NSString *tmpString1 = [tempArray objectAtIndex:1];
NSLog(#"String at index 1 = %#", tmpString1);
You may also wish to do an IF statement to check tmpArray actually contains objects in before attempting to grab its value...
e.g.
if ([tempArray count] >= 2) {
// do the above...
}

storing an array

I am trying to store the outcome of a string from the array hypothesis into myArray
am I doing anything wrong?
myArray = [NSString stringWithFormat:#"%#", hypothesis];
Update
NSMutableArray *myArray
NSMutableArray *urArray
// this is where my words are converted into strings. e.g. if I said "HELLO"
- (void) pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis{
if (x==1){
// I am trying to store "HELLO" into myArray for comparison later.
myArray = [NSString stringWithFormat:#"%#", hypothesis];
// this would print "HELLO"
self.textview.text = [NSString stringWithFormat:#"You said %#",hypothesis];
}
else {
urArray = [NSString stringWithFormat:#"%#", hypothesis];
}
}
this is basically it. after that I will compare myArray == urArray in an ifelse statement.
Try...
myArray = [NSArray arrayWithObject:[NSString stringWithFormat:#"%#", hypothesis]];
Yes, you are doing several things wrong.
you have a method -pocketsphinxDidReceiveHypothesis which you have defined as taking a single argument of type NSString*, the argument is called hypothesis.
In your question you say
I am trying to store the outcome of a
string from the array hypothesis
Which suggests that you know hypothesis is an array, but we can't verify this as you don't show that piece of code.
hypothesis must be a String or an Array. It cannot be both, you cannot be unsure.
If hypothesis is a String, ie. if you do something like:
NSString *input = #"Hello World";
[foo pocketsphinxDidReceiveHypothesis: input];
Then these two lines make no sense:-
NSMutableArray *myArray = [NSString stringWithFormat:#"%#", hypothesis];
NSMutableArray *urArray = [NSString stringWithFormat:#"%#", hypothesis];
Because, well look..
NSString *hypothesis = #"Hello World";
newString = [NSString stringWithFormat:#"%#", hypothesis];
This code does nothing, hypothesis and newString are identical, as you haven't even provided any arguments for the format. [NSString stringWithFormat:#"%#", hypothesis] is no different to just using hypothesis. So what you actually have is
NSString *hypothesis;
NSMutableArray *myArray = hypothesis;
NSMutableArray *urArray = hypothesis;
This is broken, you cant assign a String to an Array (well, i'm fairly certain you don't mean to anyhow). To use an Array you must use of of the several Array creation methods to give you, well, an Array. A String isn't an Array and can't pretend to be one.
Now, apologies if hypothesis isn't a String but is infact an Array (it would have helped if you had shown that piece of code). If it is an Array, ie. you do something like this..
NSArray *input = [NSArray arrayWithObject:#"Hello World"];
[foo pocketsphinxDidReceiveHypothesis: input];
Then your method definition is broken because you have defined it as taking a String argument
- (void)pocketsphinxDidReceiveHypothesis:(NSString *)hypothesis
When you need it to take an Array argument
- (void)pocketsphinxDidReceiveHypothesis:(NSArray *)hypothesis
Then the following two lines make no sense:-
NSMutableArray *myArray = [NSString stringWithFormat:#"%#", hypothesis];
NSMutableArray *urArray = [NSString stringWithFormat:#"%#", hypothesis];
[NSString stringWithFormat:#"%#", hypothesis] is exactly the same as [hypothesis description], which returns a String, so what you are effectively doing is:
NSArray *hypothesis;
NSString *hypothesisDescription = [hypothesis description];
NSMutableArray *myArray = hypothesisDescription;
NSMutableArray *urArray = hypothesisDescription;
So again, assigning a String to an Array variable - almost certainly not going to do what you want or need.
If hypothesis is a String and you meant to add it to an array, you must first make sure the array is initialized (ie it has to be a valid array). Something like NSMutableArray *myArray = [[NSMutableArray alloc] init] will do the trick. Then you can use one of NSMutableArray's methods to store your String, eg. [myArray addObject:hypothesis].
If hypothesis is an Array would you like to store the it in myArray as is or would you first like to transform it into a String?
Then you go on to say:-
I will compare myArray == urArray in
an ifelse statement
Given the confusion surrounding the preceding code it is not clear why you want to do this or what you hope to achieve. You have nowhere included a description of what this code is supposed to do. It is not clear whether you are aware that two Arrays that contain identical objects are not == (as the are two different arrays and have their own identity), but two pointers to the same Array are ==, eg:
NSArray *aSimpleArray = [NSArray arrayWithObjects:#"one", #"two", #"three", nil];
NSArray *foo = aSimpleArray;
BOOL result = (aSimpleArray==foo); // These are equal, result is true
NSArray *anotherSimpleArray = [NSArray arrayWithObjects:#"one", #"two", #"three", nil];
BOOL result = (aSimpleArray==anotherSimpleArray); // These are not equal, result is false
So unless you want to test if you have two pointers to the same Array (and not just two arrays with the same objects) == probably doesn't do what you want. Note there are methods to help compare Arrays, such as -isEqualToArray, so that:
NSArray *aSimpleArray1 = [NSArray arrayWithObjects:#"one", #"two", #"three", nil];
NSArray *aSimpleArray2 = [NSArray arrayWithObjects:#"one", #"two", #"three", nil];
BOOL areEqual1 = aSimpleArray1==aSimpleArray2; // FALSE
BOO areEqual2 = [aSimpleArray1 isEqualToArray:aSimpleArray2]; // TRUE
In general you have to be familiar with the interfaces of all the objects you are going to use
http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Classes/NSArray_Class/NSArray.html
The Apple documentation is excellent but i recommend a good book. There are many posts about book recommendations on SO so i leave that to you. Otherwise Apple provides hundreds of simple sample projects that you should study.
Are you trying to add hypothesis to one of your arrays (i.e. your arrays are arrays of multiple hypotheses)? If so then you can use addObject:
[myArray addObject:hypothesis];
If the hypothesis string is actually supposed to represent the entire array then you'll need to explain how the elements are encoded into this string before we can help you.
I am trying to store the same text
that hypothesis is holding into
myArray.
In that case:
NSArray *myArray = nil;
…
myArray = [NSArray arrayWithObject:hypthesis];
But mainly I would suggest that you go through some good Objective-C tutorial, since you seem to be confusing many basic ideas and it’s hard to get somewhere without knowing the basics.