How do you change the elements within an NSArray? - objective-c

I am a bit confused as to how arrays are handled in Objective-C.
If I have an array such as
NSarray *myArray = [[NSArray alloc]
initWithObjects:#"N", #"N", #"N", #"N", #"N",
nil];
how do I change the first occurrence to "Y"?

You need an NSMutableArray ..
NSMutableArray *myArray = [[NSMutableArray alloc]
initWithObjects:#"N", #"N", #"N", #"N", #"N",
nil];
and then
[myArray replaceObjectAtIndex:0 withObject:#"Y"];

You can't, because NSArray is immutable. But if you use NSMutableArray instead, then you can. See replaceObjectAtIndex:withObject::
[myArray replaceObjectAtIndex:0 withObject:#"Y"]

Write a helper method
-(NSArray *)replaceObjectAtIndex:(int)index inArray:(NSArray *)array withObject:(id)object {
NSMutableArray *mutableArray = [array mutableCopy];
mutableArray[index] = object;
return [NSArray arrayWithArray:mutableArray];
}
Now you can test this method with
NSArray *arr = #[#"a", #"b", #"c"];
arr = [self replaceObjectAtIndex:1 inArray:arr withObject:#"d"];
logObject(arr);
This outputs
arr = (
a,
d,
c
)
You can use similar method for NSDictionary
-(NSDictionary *)replaceObjectWithKey:(id)key inDictionary:(NSDictionary *)dict withObject:(id)object {
NSMutableDictionary *mutableDict = [dict mutableCopy];
mutableDict[key] = object;
return [NSDictionary dictionaryWithDictionary:mutableDict];
}
You can test it with
NSDictionary *dict = #{#"name": #"Albert", #"salary": #3500};
dict = [self replaceObjectWithKey:#"salary" inDictionary:dict withObject:#4400];
logObject(dict);
which outputs
dict = {
name = Albert;
salary = 4400;
}
You could even add this as a category and have it easily available.

Related

NSDictionary and NSArray

I have arrays of names and images like below
NSArray *names = [[NSArray alloc] initWithObjects:#"naveen", #"kumar",nil];
NSArray *images = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"1.jpg"], [UIImage imageNamed:#"2.jpg"], nil];
I want to create a dictionary in the following format
list:
item 0 : naveen
1.jpg
item 1: kumar
2.jpg
How can i create this one? Please?
You need to do like this :
NSMutableDictionary *nameImageDict=[NSMutableDictionary new];
for (NSInteger i=0; i<names.count; i++) {
NSArray *array=#[names[i],images[i]];
//or in older compiler 4.3 and below
//NSArray *array=[NSArray arrayWithObjects:[names objectAtIndex:i],[images objectAtIndex:i], nil];
[nameImageDict setObject:array forKey:[NSString stringWithFormat:#"item %d",i]];
}
for key item 0: it will have an array. The array contains name and image.
Like this:
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:images andKeys:names];
Like this
NSDictionary * list = [NSDictionary dictionaryWithObjects:images forKeys:names];

NSMutableArray multidimensional, get a column

i have a NSArray created with a Dictionary:
aMapData = [[NSMutableArray alloc] initWithCapacity:sizeof(jsonResponse)];
for (NSMutableDictionary *dict in jsonResponse) {
NSDictionary *row = [NSDictionary dictionaryWithObjectsAndKeys:[dict objectForKey:#"pID"], #"pID", [dict objectForKey:#"Address"], #"Address", nil];
[aMapData addObject:row];
}
It has about 100 rows.
I want to get the pID column, is the only option the iteration and:
[aMapData objectAtIndex:0]
?
Thank you in advance!
I found it, is not necessary an array:
NSArray *idPath = [aMapData valueForKey:#"pID"];
Yes. Otherwise you have to store each column in a separate array.
pID = [[NSMutableArray alloc] init];
address = [[NSMutableArray alloc] init];
for (NSMutableDictionary *dict in jsonResponse) {
[pID addObject:[dict objectForKey:#"pID"]];
[address addObject:[dict objectForKey:#"address"]];
}

Sort NSMutableArray with strings that contain numbers?

I have a NSMutableArray and it has the users high scores saved into it. I want to arrange the items numerically (the numbers are stored in NSStrings.)Example:4,2,7,8To2,4,7,8What is the simplest way to do this if the data is stored in NSStrings?
This code will do it:
//creating mutable array
NSMutableArray *myArray = [NSMutableArray arrayWithObjects:#"4", #"2", #"7", #"8", nil];
//sorting
[myArray sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
return [str1 compare:str2 options:(NSNumericSearch)];
}];
//logging
NSLog(#"%#", myArray);
It uses blocks, make sure your target OS supports that (It's 4.0 for iOS and 10.6 for OSX).
This code works. I tried it:
NSMutableArray *unsortedHighScores = [[NSMutableArray alloc] initWithObjects:#"4", #"2", #"7", #"8", nil];
NSMutableArray *intermediaryArray = [[NSMutableArray alloc] init];
for(NSString *score in unsortedHighScores){
NSNumber *scoreInt = [NSNumber numberWithInteger:[score integerValue]];
[intermediaryArray addObject:scoreInt];
}
NSArray *sortedHighScores = [intermediaryArray sortedArrayUsingSelector:#selector(compare:)];
NSLog(#"%#", sortedHighScores);
The output is this:
2
4
7
8
If you have any questions about the code, just ask in the comments. Hope this helps!
The NSMutableArray method sortUsingSelector: should do it:
[scoreArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)]
should do it.
If the array is of nsdictionaries conaining numeric value for key number
isKeyAscending = isKeyAscending ? NO : YES;
[yourArray sortUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
NSString *str1 = [obj1 objectForKey:#"number"];
NSString *str2 = [obj2 objectForKey:#"number"];
if(isKeyAscending) { //ascending order
return [str1 compare:str2 options:(NSNumericSearch)];
} else { //descending order
return [str2 compare:str1 options:(NSNumericSearch)];
}
}];
//yourArray is now sorted
The answer from Darshit Shah make it smootly
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc]initWithKey:#"rank" ascending:YES selector:#selector(localizedStandardCompare:)];

How can I retrieve all the contents of an NSDictionary?

I want to select and retrieve all the contents from an NSDictionary. I have a structure like this
- (void)viewDidLoad {
[super viewDidLoad];
listaOggetti = [[NSMutableArray alloc] init];
NSArray *arrayOne = [NSArray arrayWithObjects: #"First",#"Second",#"Third", nil];
NSArray *sortedOne = [arrayOne sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSDictionary *dictOne = [NSDictionary dictionaryWithObject:sortedOne forKey:#"Elementi"];
NSArray *arrayTWo = [NSArray arrayWithObjects:#"First1",#"Second1" ..., nil];
NSArray *sortedTwo = [arrayTwo sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSDictionary *dictTwo = [NSDictionary dictionaryWithObject:sortedTWo forKey:#"Elementi"];
NSArray *arrayThree = [NSArray arrayWithObjects:#"First2",#"Second2" ... , nil];
NSArray *sortedThree = [arrayThree sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSDictionary *dictThree = [NSDictionary dictionaryWithObject:sortedThree forKey:#"Elementi"];
[listaOggetti addObject:dictOne];
[listaOggetti addObject:dictTwo];
[listaOggetti addObject:dictThree];
}
And I want to retrieve all the objects for the key #"Elementi" (should be around 45) in order to add them in another array, like:
NSDictionary *dict = [listaOggetti objectAtIndex:indexPath.section];
NSArray *array = [dict objectForKey:#"Elementi"];
cellValue = [array objectAtIndex:indexPath.row] ;
(With this, dict is only 9 objects filled in my project).
At the end, the *array should be around 45 objects filled. I tried with allValues, but didn't work.
How can I fix it?
The easiest is to do this in -viewDidLoad:
NSMutableArray *allObjects = [[NSMutableArray alloc] init];
[allObjects addObjectsFromArray:sortedOne];
[allObjects addObjectsFromArray:sortedTwo];
[allObjects addObjectsFromArray:sortedThree];
Alternately, you can get them from the dictionaries in a similar fashion:
NSMutableArray *allObjects = [[NSMutableArray alloc] init];
[allObjects addObjectsFromArray:[[listaOggetti objectAtIndex:0] objectForKey#"Elementi"];
[allObjects addObjectsFromArray:[[listaOggetti objectAtIndex:1] objectForKey#"Elementi"];
[allObjects addObjectsFromArray:[[listaOggetti objectAtIndex:2] objectForKey#"Elementi"];
What you are failing to understand is that listaOggetti is an NSMutableArray containing three objects. When you call
NSDictionary *dict = [listaOggetti objectAtIndex:indexPath.section];
the result is that dict is a single dictionary, one of the three objects in listaOggetti. Therefore when you call
NSArray *array = [dict objectForKey:#"Elementi"];
the result is that array is the object for the key #"Elementi" of that one single dictionary dict. Your code makes no attempt to combine the three DIFFERENT dictionaries or to combine the three arrays, each set as objectForKey:#"Elementi" for the three DIFFERENT dictionaries.
If you want one array that is the concatenation of all three different arrays, then use one of the snippets provided above. In both of these snippets, the result is that allObjects is an NSMutableArray containing all three arrays, in order.

Remove all strings with duplicates in an NSArray

I am trying to figure out how to implement this in Objective-C.
I want to remove the strings in an NSArray that have appear more than once in the array.
At the end I want to have an array that only has the unique lines in an array (meaning that not just the duplicates are deleted but also the original string that matches the duplicates.)
For example if you had the following array:
NSArray *array = [NSArray arrayWithObjects:#"bob", #"frank", #"sarah", #"sarah", #"fred", #"corey", #"corey", nil];
I would want the new array to look like this:
#"bob", #"frank", #"fred"
Use an NSCountedSet:
NSCountedSet *countedSet = [NSCountedSet setWithArray:yourArray];
NSMutableArray *finalArray = [NSMutableArray arrayWithCapacity:[yourArray count]];
for(id obj in countedSet) {
if([countedSet countForObject:obj] == 1) {
[finalArray addObject:obj];
}
}
#Caleb suggested adding a method to NSCountedSet called -objectsWithCount:,, which I've implemented here:
#interface NSCountedSet (JRCountedSetAdditions)
- (NSArray *) objectsWithCount:(NSUInteger) count;
#end
#implementation NSCountedSet (JRCountedSetAdditions)
- (NSArray *) objectsWithCount:(NSUInteger) count {
NSMutableArray *array = [NSMutableArray array];
for(id obj in self) {
if([self countForObject:obj] == count) {
[array addObject:obj];
}
}
return [array copy];
}
#end
Once that's done, all you need is one line:
NSArray *finalArray = [[NSCountedSet setWithArray:yourArray] objectsWithCount:1];
By the way, this is type-agnostic, so this will work with any Objective-C object. :-)
One liner : uniqueArray = [[NSSet setWithArray:duplicateArray] allObjects]; if you don't care about the ordering :D
A slightly different approach from Jacob's:
NSArray *array = [NSArray arrayWithObjects:#"bob", #"frank", #"sarah", #"sarah", #"fred", #"corey", #"corey", nil];
NSCountedSet *namesSet = [[NSCountedSet alloc] initWithArray:array];
NSMutableArray *namesArray = [[NSMutableArray alloc] initWithCapacity:[array count]];
[namesSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
if ([namesSet countForObject:obj] == 1) {
[namesArray addObject:obj];
}
}];
And
NSLog(#"old: %#\nNew: %#", array, namesArray);
gives:
2011-06-16 18:10:32.783 SetTest[1756:903] old: (
bob,
frank,
sarah,
sarah,
fred,
corey,
corey
)
New: (
frank,
fred,
bob
)
Blocks are your friends! And since NSCountedSet is a subclass of NSSet you can use the block methods that are available there.
Here is the simplest approach to remove duplicate strings:
NSArray *array = [NSArray arrayWithObjects:#"bob", #"frank", #"sarah", #"sarah", #"fred", #"corey", #"corey", nil];
NSArray *distintStrings = [array valueForKeyPath:#"#distinctUnionOfObjects.self"];