Adding strings to an array in for loop and not overwrite the value in objective-c - objective-c

I define a NSMutableArray *nameArray in .h file. And add strings using this nameArray in a for loop in .m file like below:
for (int i=0; i<[data count]; i++) {
NSDictionary* place = [data objectAtIndex:i];
NSString *name=[place objectForKey:#"name"];
_nameArray = [[NSMutableArray alloc] init];
[_nameArray addObject:name];
}
NSLog(#"After loop, Name is %#", _nameArray);
Actually, it should have several names in this array. But why it only output one name which was added in the array last?

You must create your array outside the loop, that is your problem.
// Init array
_nameArray = [[NSMutableArray alloc] init];
// Fill array
for (int i=0; i<[data count]; i++) {
NSDictionary* place = [data objectAtIndex:i];
NSString *name=[place objectForKey:#"name"];
[_nameArray addObject:name];
}
// Log array
NSLog(#"After loop, Name is %#", _nameArray);
All of your objects are added to an own array and only the last array will not be overwritten and is therefore in the log.

Related

Why does replaceObjectAtIndex depend on whether or not I use a new definition in the loop?

I have two codes. Not working is the following:
NSMutableArray *tmpArray = [[NSMutableArray alloc] init];
for (int i=0; i<[dataSetArray count]; i++) {
tmpArray = (NSMutableArray *) [dataSetArray objectAtIndex:i];
// OR use: tmpArray = dataSetArray[i]
... doing stuff
[tmpArray replaceObjectAtIndex:0 withObject:tmpStr];
}
While this works:
for (int i=0; i<[dataSetArray count]; i++) {
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithArray:[dataSetArray objectAtIndex:i]];
... doing stuff
[tmpArray replaceObjectAtIndex:0 withObject:tmpStr];
}
Two questions:
The first code doesn't yield an NSMutableArray. Why? I declare it
above.
Is there a better way to obtain the same result. I just
dislike defining variables in a loop. This makes the code
unreadable.
--- edit:
Here the full code:
Datatypes are:
dataSetArray: NSMutableArray. However, its contents (i.e. dataSetArray[i]) are NSArrays (I read them into the program from an excel file).
NSString *tmpStr = [[NSString alloc] init];
for (int i=0; i<[dataSetArray count]; i++) {
NSMutableArray *tmpArray = [[NSMutableArray alloc] initWithArray:[dataSetArray objectAtIndex:i]];
for (int j=0; j<[tmpArray count]; j++) {
if ( [dataSetArray[0][j] isEqualToString:#"Number"] ) {continue;}
tmpStr = (NSString *) [tmpArray objectAtIndex:j];
// replace single backslash by double-backslash:
tmpStr = [tmpStr stringByReplacingOccurrencesOfString:#"\\" withString:#"\\\\"];
// replace first dollar sign by "<p>\\[" and second by "\\]</p>"
// Use a methode defined in the NSString+Extension
tmpStr = [tmpStr replaceTexFormulaSigns:tmpStr];
//NSLog(#"j=%d", j);
//NSLog(#"tmpArray is of type: %#", [tmpArray class]);
//NSLog(#" tmpStr is of type: %#", [tmpStr class]);
[tmpArray replaceObjectAtIndex:j withObject:tmpStr];
}
[dataSetArray replaceObjectAtIndex:i withObject:tmpArray];
}
So even if I use your suggestion, I am still facing the same problem with the inner array.
The first code doesn't yield a NSMutableArray. Why? I declare it above.
The declaration of the reference variable tmpArray does not change the type of the referred object. It is still an (immutable) array.
The creation of the mutable array at the very beginning of the first snippet is without any meaning, because the reference to it is overridden.
Is there a better way to obtain the same result. I just dislike defining variables in a loop. This makes the code unreadable.
Yes. The second example works in a way, but do something completely different. (It always creates a new array with a single item in it. No, that's not true. It shouldn't compile at all.)
You should do:
NSMutableArray *tmpArray = [dataSetArray mutableCopy];
for (int i=0; i<[dataSetArray count]; i++)
{
…
[tmpArray replaceObjectAtIndex:i withObject:tmpStr];
}
You should really get some additional knowledge about objects and object references.

I need to use intermediate Array in loop

I have a basic question. I need to use intemediate array in loop. This is my code:
NSMutableArray *interArray = [[NSMutableArray alloc] initWithCapacity:2];
NSMutableArray *finalyArray = [[NSMutableArray alloc] init];
NSInteger a;
for(int j=0; j<5; j++)
{ [interArray removeAllObjects];
for(int i=0; i<2; i++)
{
a = [array ObjectAtInde:i]; // this is existing array
[interArray addObject:a];
}
[finalyArray addObject:interArray];
}
but when i delete objects in intermediate array I get empty Arrays in finaly Array. How to fix it? Thanks
The reason it won't work as you expect is because interArray is a reference to an object which you empty and fill in the loop and then add to the finalyArray, however you are adding the same intermediate array each time.
What you want to do it create a new intermediate array within the loop and therefore each intermediate array will be a separate object:
NSMutableArray *finalyArray = [[NSMutableArray alloc] init];
NSInteger a;
for(int j=0; j<5; j++)
{
NSMutableArray *interArray = [[NSMutableArray alloc] initWithCapacity:2];
for(int i=0; i<2; i++)
{
a = [array ObjectAtIndex:i]; // this is existing array
[interArray addObject:a];
}
[finalyArray addObject:interArray];
}
(Note this code won't work anyway as you cannot store NSInteger in a collection class without first wrapping it in a NSNumber object).

All objects in array (interpreted from csv) being returned as the same object (the last object)

What I am trying to achieve, is to convert a csv file into an array of custom objects, however, my attempts at this seem to result in all of the objects in the array being returned as the same object (the last object in the array).
Before I explain further, here is the code:
- (NSArray *)arrayFromCSVFileName:(NSString *)csvFileName fileType:(NSString *)fileType {
// Convert the file into an NSData object
NSString *studentFilePath = [[NSBundle mainBundle] pathForResource:csvFileName ofType:fileType];
NSData *studentData = [NSData dataWithContentsOfFile:studentFilePath];
// Convert the NSData into an NSString
NSString *csvString = [[NSString alloc] initWithData:studentData encoding:NSUTF8StringEncoding];
// Split each record (line) in the csvDataString into an individual array element (split on the newline character \n)
NSArray *csvArray = [csvString componentsSeparatedByString:#"\n"];
// Create an array to hold the parsed CSV data
NSMutableArray *parsedCSVArray = [[NSMutableArray alloc] init];
NSMutableArray *elementArray = [[NSMutableArray alloc] init];
CGSElement *elementToAdd = [[CGSElement alloc] init];
// Loop through each line of the file
for (int i = 0; i < [csvArray count]; i++) {
// Get a reference to this record (line) as a string, and remove any extranous new lines or alike
NSString *csvRecordString = [[csvArray objectAtIndex:i] stringByReplacingOccurrencesOfString:#"\r" withString:#""];
// Split the line by the comma delimeter
NSArray *csvRecordArray = [csvRecordString componentsSeparatedByString:#","];
// Check that there are actually fields (i.e. this is not a blank line)
if ( ([csvRecordArray count] > 0) && ([[csvRecordArray objectAtIndex:0] length] > 0) ) {
elementToAdd.mass = [[csvRecordArray objectAtIndex:1] floatValue];
elementToAdd.atomicNumber = [[csvRecordArray objectAtIndex:0] intValue];
elementToAdd.name = [csvRecordArray objectAtIndex:2];
elementToAdd.symbol = [csvRecordArray objectAtIndex:3];
elementToAdd.period = [[csvRecordArray objectAtIndex:4] intValue];
[elementArray addObject:elementToAdd];
}
}
for (int i = 0; i < [elementArray count]; i++) {
NSLog(#"%i", i);
CGSElement *current = [elementArray objectAtIndex:i];
NSLog(#"Name = %#", current.name);
}
// Return the parsed array
return elementArray;
}
The custom object in question is the CGSElement object, which I am attempting to fill the elementArray with. However, my debug code (the following section of code):
for (int i = 0; i < [elementArray count]; i++) {
NSLog(#"%i", i);
CGSElement *current = [elementArray objectAtIndex:i];
NSLog(#"Name = %#", current.name);
}
Is resulting, rather than in the return of all of the correct element names, it is returning the last element (to put this in context, ununoctium), 118 times.
After some testing, I can safely say that up until after this point:
elementToAdd.mass = [[csvRecordArray objectAtIndex:1] floatValue];
elementToAdd.atomicNumber = [[csvRecordArray objectAtIndex:0] intValue];
elementToAdd.name = [csvRecordArray objectAtIndex:2];
elementToAdd.symbol = [csvRecordArray objectAtIndex:3];
elementToAdd.period = [[csvRecordArray objectAtIndex:4] intValue];
All of the elements are being correctly defined, rather than just the same element over and over.
Needless to say, I'm stumped as to why it would be returning the same object over and over. Any help would be appreciated.
This line:
CGSElement *elementToAdd = [[CGSElement alloc] init];
Should be inside your loop, just before you try to edit the object and add it to the array. Currently you are repeatedly mutating the same object instead of creating new objects for each record.
You add the same entity all the time. It is crated once before the loop and within the loop it values are changed again and angan and it is added to the array. Naturally all items in the aray carry the same values because it is the same object.
If you want then change the array with an NSSet. To a set an object can only added once and you will end up with a set of 1. That is not the solution of couse, it would just visualize what is happening.
To solve it move this line
CGSElement *elementToAdd = [[CGSElement alloc] init];
to the beginning of the body of the for i loop, so that a new instance is created for every iteration and therefore for every index of the array.

Method Creates an Array with 11 objects, All Out of Scope, Unrecognized Selector Results

Okay, so, I'm doing a simple lookup. I have an array of NSString objects and a string to search for in the array's elements.
It all seems to work up until I try to add a match to a new mutable array made to hold the search results. The stringHolder variable gets the string, and resultsCollectorArray even get the right number of new elements, but each element is empty and "out of range". Here's the method:
#implementation NSArray (checkForString)
-(NSMutableArray *) checkForString: (NSString *) matchSought
{
long unsigned numberofArrayElements;
long unsigned loop = 0;
NSRange searchResults;
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init];
id stringHolder;
numberofArrayElements = [self count];
while (loop < numberofArrayElements) {
searchResults.length = 0;
searchResults = [[self objectAtIndex: loop] rangeOfString: matchSought options:NSCaseInsensitiveSearch];
if (searchResults.length > 0) {
stringHolder = [self objectAtIndex: loop];
[resultCollectorArray addObject: stringHolder];
}
loop++;
}
return [resultCollectorArray autorelease];
}
Once we get back to the main portion of the program, I get an unrecognized selector sent to the mutable array that was supposed to receive the result of the method. Here's the main section:
#import <Foundation/Foundation.h>
#import "LookupInArray.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testString = [[NSString alloc] initWithString: #"ab"];
NSMutableString * resultString = [[NSString alloc] init];
NSArray * theArray = [[NSArray alloc] initWithObjects: ..., nil]; // Actual code has the objects
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSUInteger arrayCount = 0;
unsigned long loops = 0;
resultArray = [theArray checkForString: testString];
arrayCount = [resultArray count];
while (loops < arrayCount){
resultString = [resultArray objectAtIndex: loops]; // Here's where we get the unrecognized selector.
NSLog(#"%#", resultString);
loops++;
}
[pool drain]; // Also, I'll release the objects later. I just want to get what's above working first.
return 0;
}
I've searched the other answers (for hours now), but didn't seen anything that solved the issue.
Any and all help would be really appreciated.
And thanks beforehand.
NSMutableArray * resultCollectorArray = [[NSMutableSet alloc] init]; is so incorrect. You are creating a mutable set and assigning it to a mutable array.
You are getting unrecognized selector because objectAtIndex: is not a valid selector for NSMutableSet. Make that statement,
NSMutableArray * resultCollectorArray = [[NSMutableArray alloc] init];
A Better way
NSArray * filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF contains[cd] %#", searchString]];
You can directly filter the array using predicates. This way you do this in a single step. :)

Create multiple numbered variables based on a int

How would I create a number of NSDictionary variables using an array's count?
This is basically what I came up with, but I'm not sure how to make this work with Objective-C syntax. doesntContainAnother is an NSArray. I want the names of the dictionaries to use the current value of loopInt.
int *loopInt = 0;
while (doesntContainAnother.count <= loopInt) {
NSMutableDictionary *[NSString stringWithFormat:#"loopDictionary%i", loopInt] = [[[NSMutableDictionary alloc] init] autorelease];
[NSString stringWithFormat:#"loopDictionary%i", loopInt] = [NSDictionary dictionaryWithObject:[array1 objectAtIndex:loopInt]
forKey:[array2 objectAtIndex:loopInt]];
loopInt = loopInt + 1;
}
Create a mutable array and loop until you reach the original array's count, creating a dictionary and adding it to the mutable array on each iteration.
Your code should look like this.
NSMutableArray *dictionaries = [[NSMutableArray alloc] init];
for (int i = 0; i < doesntContainAnother.count; i++) {
[dictionaries addObject:[NSMutableDictionary dictionaryWithObject:[array1 objectAtIndex:i] forKey:[array2 objectAtIndex:i]]];
}
The approach of creating variables with numbers at the end of their names is an antipattern and not even possible in Objective-C. It's equivalent to an array, but clunkier.
You need to create a mutable array, and then put the objects into the array. You can't create a variable with the same name as the contents of a string, as you have done. For example:
NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity:[doesntContainAnother count]];
int i = 0; // Note: type is int, not int*
for (i = 0; i < [doesntCountainAnother count]; i++) {
[arr addObject:[NSMutableDictionary dictionary]];
}
// Later...
NSMutableDictionary *d1 = [arr objectAtIndex:3];
Or if you want to pull them out of the list by name:
NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:[doesntCountainAnother count]];
int i = 0;
for (i = 0; i < [doesntContainAnother count]; i++) {
[dict setObject:[NSMutableDictionary dictionary] forKey:[NSString stringWithFormat:#"loopDictionary%d", i]];
}
// Later...
NSMutableDictionary *d1 = [dict objectForKey:#"loopDictionary3"];
But the first way is likely the easiest.