I have NSMutableArray with 10,000 objects, each object has Name, Details, ...etc.
I want to Create an NSArray Which contains ONLY the Names of all objects.
Use KVC
NSArray *names = [myArray valueForKey:#"name"];
Check the docs for NSArray
valueForKey:
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects.
Related
I have a NSDictionary that I get from a webservice. Each object in this dictionary contains an array. I do not know how many objects there are going to be in the NSDictionary, or what the 'Key' for each object is going to be beforehand. I only know that it will be a Dictionary of arrays.
How can I enumerate through the dictionary reading out the name of the Object and its content into arrays?
All my dealings with Dictionaries so far I could use
[anotherDict objectForKey:#"accounts"]
because I know the 'Keys; to expect beforehand.
Many Thanks,
-Code
NSDictionary has the method: enumerateKeysAndObjectsUsingBlock: since iOS 4.0. It's very straightforward, it receives a block object to operate on entries in the dictionary.
An example:
[anotherDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSArray *arr = obj;
//Do something
}
NSDictionary class has an instance method -allKeys which returns an NSArray with NSStrings for all the keys.
Simplest Way WOuld be to fetch allKeys via the allKeys instance method
NSArray *keys = [myDictionary allKeys];
then iterating over dictionary with for each key.
for (NSString *k in keys)
{
id object = [myDictionary objectForKey:k];
}
You can also get keys in order as if values were sorted using
NSArray *sortedKeys = [myDictionary keysSortedByValueUsingSelector:#selector(compare:)];
you can do this :
NSArray * keys = [dictionnary allKeys];
for (NSString *key in keys) {
NSArray *tmp = [dictionnary objectForKey:key];
}
i am not a pro but i know that you can get all the keys of an dictionary
NSLog(#"%#",[Your_Dictionary allKeys]);
This will give an array of keys in that dictionary.
I am using one NSMutableArray with same string object.
Here is the code
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:#"hello",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",nil];
NSObject *obj = [arr objectAtIndex:2];
[arr removeObject:obj];
NSLog(#"%#",arr);
When i try to remove 3rd object of array, its removing all object with "hi" string.
I am not getting why its happening.
my doubt is while removing object, NSMutableArray match string or address.
It's because you're using removeObject which removes all objects that are "equal" to the one you pass in. As per this Apple documentation:
This method uses indexOfObject: to locate matches and then removes
them by using removeObjectAtIndex:. Thus, matches are determined on
the basis of an object’s response to the isEqual: message. If the
array does not contain anObject, the method has no effect (although it
does incur the overhead of searching the contents).
You're seeing the effects of literal strings here where each of those #"hi" objects will turn out to be the same object just added many times.
What you really want to do is this:
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:#"hello",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",nil];
[arr removeObjectAtIndex:2];
NSLog(#"%#",arr);
Then you're specifically removing the object at index 2.
According to https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html
removeObject:
Removes all occurrences in the array of a given object.
which is exactly the behaviour you're seeing. If you want to remove the object at a particular position, you want removeObjectAtIndex:.
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:#"hello",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",#"hi",nil];
NSUInteger obj = [arr indexOfObject:#"hi"]; //Returns the lowest integer of the specified object
[arr removeObjectAtIndex:obj]; //removes the object from the array
NSLog(#"%#",arr);
I am facing a very regular scenario.
I have an NSArray which has object of a custom type, say Person. The Person class has the attributes: firstName, lastName and age.
How can I get an NSArray containing only one attribute from the NSArray having Person objects?
Something like:
NSArray *people;
NSArray *firstNames = [people getArrayOfAttribute:#"firstName" andType:Person.Class]
I have a solution of writing a for loop and fill in the firstNames array but I don't want to do that.
NSArray will handle this for you using KVC
NSArray *people ...;
NSArray *firstName = [people valueForKey:#"firstName"];
This will give you an array of the firstName values from each entry in the array
Check out the filterUsingPredicate: method in NSMutableArray, basically you create a NSPredicate object that will define how the array will be filtered.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pUsing.html#//apple_ref/doc/uid/TP40001794-CJBDBHCB
This guide will give you an overview, and has a section for dealing with arrays.
You can also use block based enumeration:
NSArray *people; // assumably has a bunch of people
NSMutableArray *firstNames = [NSMutableArray array];
[people enumerateObjectsUsingBlock:
^(id obj, NSUInteger idx, BOOL*flag){
// filter however you want...
[firstNames addObject:[Person firstName]];
}];
The benefit is it is fast and efficient if you have a bunch of people...
OK, this is a bit obscure, but it's giving me a headache.
If you have an array of strings
{#"1", #"2", #"4"}
And you have a array of Recipe objects
{ {recipe_name:#"Lasagna", recipe_id:#"1"}
{recipe_name:#"Burger", recipe_id:#"2"}
{recipe_name:#"Pasta", recipe_id:#"3"}
{recipe_name:#"Roast Chicken", recipe_id:#"4"}
{recipe_name:#"Sauerkraut", recipe_id:#"5"}
}
How would I, using the first array, create an array like this:
{#"Lasagna", #"Burger", #"Roast Chicken"}
In ither words, it is taking the numbers in the first array and creating an array of recipe_names where the recipe_id matches the numbers...
Use an NSPredicate to specify the type of objects you want, then use -[NSArray filteredArrayUsingPredicate:] to select precisely those objects:
NSArray *recipeArray = /* array of recipe objects keyed by "recipe_id" strings */;
NSArray *keyArray = /* array of string "recipe_id" keys */;
NSPredicate *pred = [NSPredicate predicateWithFormat:#"recipe_id IN %#", keyArray];
NSArray *results = [recipeArray filteredArrayUsingPredicate:pred];
NSPredicate uses its own mini-language to build a predicate from a format. The format grammar is documented in the "Predicate Programming Guide."
If you are targeting iOS 4.0+, a more flexible alternative is to use -[NSArray indexesOfObjectsPassingTest:]:
NSIndexSet *indexes = [recipeArray indexesOfObjectsPassingTest:
^BOOL (id el, NSUInteger i, BOOL *stop) {
NSString *recipeID = [(Recipe *)el recipe_id];
return [keyArray containsObject:recipeID];
}];
NSArray *results = [recipeArray objectsAtIndexes:indexes];
Your array of recipe objects is basically a dictionary:
NSDictionary *recipeDict =
[NSDictionary dictionaryWithObjects:[recipes valueForKey:#"recipe_name"]
forKeys:[recipes valueForKey:#"recipe_id"]];
And on a dictionary you can use the Key-Value Coding method:
NSArray *result = [[recipeDict dictionaryWithValuesForKeys:recipeIDs] allValues];
Assuming that your Recipe objects are key-value compliant (which they almost always are) you can use a predicate like so:
NSArray *recipes= // array of Recipe objects
NSArray *recipeIDs=[NSArray arrayWithObjects:#"1",#"2",#"3",nil];
NSPredicate *pred=[NSPredicate predicateWithFormat:#"recipe_id IN %#", recipeIDs];
NSArray *filterdRecipes=[recipes filteredArrayUsingPredicate:pred];
NSArray *recipeNames=[filterdRecipes valueForKey:#"recipe_name"];
Is it acceptable to have a NSMutableArray within an NSDictionary? Or does the NSDictionary also have to be mutable?
The NSMutableArray will have values added to it at runtime, the NSDictionary will always have the same 2 NSMutableArrays.
Thanks,
Dan
Yes, it's perfectly acceptable. Keep in mind, the contents of the array are the pointers to your NSMutableArrays--those are what can't change in the immutable dictionary structure. What the pointers point to can change all you want. To wit:
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSDictionary *dict = [NSDictionary dictionaryWithObject:arr forKey:#"test"];
[arr addObject:#"Hello"];
NSString *str = [[dict objectForKey:#"test"] objectAtIndex:0];
NSLog("%#", str);
It's quite acceptable. But, it's precisely the sort of setup that suggests you should seriously consider replacing the dictionary with an NSObject subclass that sports two properties for accessing the arrays.