I have an array of Person objects (which has a number of attributes). I want to make another array with just the Person's "fullname" attribute. Is there a simple way to do this, other than the obvious one: iterate over the original array, and copy over the fullname one-by-one into another array? Can we do this initWithArray: and tell it to use the object's fullname property when copying?
NSArray indeed has built-in method for that:
NSArray *nameArray = [personArray valueForKey:#"fullname"];
Related
I came across NSFrozenDictionary while debugging an app.
Shared index property declared as NSDictionary * sharedIndex = ...
What is it? How is it different from NSMutableDictionary?
It is an NSMutableDictionary marked as immutable.
One case to get __NSFrozenDictionaryM:
Have an array of mutable dictionaries:
NSArray *array = #[{NSMutableDictionary}, {NSMutableDictionary}, {NSMutableDictionary}]
Making a two-level-deep copy of it by:
NSArray *res = [[NSArray alloc] initWithArray:array copyItems:YES]
The resulting res array contains immutable copies of NSMutableDictionaries in array, which are of type __NSFrozenDictionaryM. I guess this is an optimisation to avoid really copying all dictionaries in the original array.
It is one of the concrete subclasses that is part of the NSDictionary class cluster.
There is a more academic description on Apple's documentation site.
Essentially: don't worry about it. If you declared it as a plain NSDictionary, then treat it as such: an immutable dictionary. Foundation may create something else under the hood for optimization purposes, but as far as your code is concerned, it's still an immutable dictionary.
I have an array and would like to append N items from another array to it, but only the items not already exist in the current array.
Note, the uniqueness of item is determined not by the object memory but its content. For example, I can have two distinct objects called Person with name "David" and I only one of this in my final result.
What's an efficient way to do this? I have looked at the options of doing it using NSPredicate and NSOrderedSet.
[#[arrayOne,arrayTwo] valueForKeyPath:#"#distinctUnionOfArrays.name"] where name is the property to merge the arrays with.
See NSHipster's KVC Collection Operators
Can be easily achieved using NSSet. Here is an example solution:
//Lines of init can be ignored. Just pay attention to the variables and their comments
NSArray * old = [[NSArray alloc]init]; //Assume this is your old array
NSArray * more = [[NSArray alloc]init]; //Assume this is your extra array
NSArray * new = [[NSArray alloc]init]; //Assume this is your new array (having duplicates)
new = [old arrayByAddingObjectsFromArray:more];
NSArray *cleanedArray = [[NSSet setWithArray:new] allObjects];
For explanation, NSSet automatically removes duplicates.
Warning: It does not preserve the order. If you want to proceed to maintain the order, sort it afterwards, or there are more complex solution on the way.
If I have an immutable NSDictionary with nested hierarchy, from a JSON string, what is the easiest way to change a value for a key that is deeply nested in the hierarchy?
For example, I have a dictionary, and the value for "key1" is an array, inside the array, each element is a dictionary, and inside each dictionary, there is a value for key "key2", now I want to change the value for "key2", since the whole data structure is immutable, which makes it difficult, should I duplicate this data structure with mutable collection so that I can change that value, this seems to have a lot of overhead, but this is the only way that came into my mind.
I don't know if this is an acceptable alternative for you, but you can create the dictionary from the JSON string with the NSJSONReadingMutableContainers option, which creates all arrays and dictionaries as mutable objects.
i'm not totally sure, but i think you'll have to pass everyone of your dictionary and array to a mutable one.
It depends if you want to still have a immutable structure after the change or if it doesn't matter if it's still mutable after it.
if you want to stay immutable after the change, then you'll have to use temp variable for mutable dict and array.
NSMutableDictionary *rootDict = [NSMutableDictionary dictionaryWithDictionary:rootImmutableDict];
NSMutableArray* mutableArray = [NSMutableArray arrayWithArray:[rootImmutableDict objectForKey:#"key1"]];
NSMutableDictionary* valueDict = [NSMutableDictionart dictionaryWithDictionary:[mutableArray objectAtIndex:idx]];
[valueDict setObject:newValueObject forKey:#"key2"];
[rootImmutableDict release];
rootImmutableDict = nil;
rootImmutableDict = [[NSDictionary alloc] initWithDictionary:rootDict];
if it doesn't matter for you if it's mutable, then you'd have to make it mutable when retrieving it from the JSON by using a temp immutable structure and make it mutable permanently.
i hope it'll be helpfull to you.
I have an NSArray consisting of NSNumbers and I want to convert this to an NSArray of NSStrings, by getting the stringValue of each NSNumber in the first array.
The method that comes to my mind is iterating each value in the first one, getting its string value and adding it into another array. But there should be a more elegant solution for this. Do you know one?
NSArray implements the Key-Value Coding method valueForKey: in such a way that it returns a new array. The new array contains the results of asking each object in the original array for the specified value. In this case, NSNumber has its stringValue, so all you have to do is:
NSArray * b = [a valueForKey:#"stringValue"];
Plain old fast enumeration (or enumerateObjectsUsingBlock:) wouldn't be a terrible solution, though. NSArray's implementation of valueForKey: most likely uses a for loop internally, and that would be pretty readily understood by anyone who reads it later.
how would i go about uniquely naming an object and adding it to an nsmutablearray most likely in a for loop?
You're confusing objects and variables. Variables have names; objects don't unless you give them some name instance variable. More to the point, the same variable can reference different objects at different times. Given some collection of objects collection:
NSMutableArray *array = [NSMutableArray array];
for (id item in collection) {
[array addObject:item];
}
This will create a mutable array with all the objects in collection, with the item variable pointing to a different object from collection on each iteration of the loop.
If you want to uniquely name instances then instead of an array how about using a NSDictionary? Then you can grab the array of keys from it. Run through this key array to get the name of a particular instance and then use that key to get the actual object instance from the dictionary.