NSSet: return an NSArray of objects sorted by a list of strings on certain property of each object? - objective-c

I have an NSSet of objects.
Each object in the set is an instance of MyObject with a property called name.
I have another NSArray called nameIndexes which contains name values.
I would like to have a function that takes the NSSet and returns a sorted array sorted using the name property based on its position in the nameIndexes array.
Edit:
Sorry for my misleading, here is an example:
I have a set of MyObject(may not be in the same order):
MyObject1 {name:#"A"}
MyObject2 {name:#"B"}
MyObject3 {name:#"C"}
I have another array of names:
{"B", "A", "C"}
I want an NSArray of:
{MyObject2, MyObject1, MyObject3}

NSSet *set = //your set.
NSArray *nameIndexes = //the array of names for sorting.
NSArray *result = [[set allObjects] sortedArrayUsingComparator:^NSComparisonResult(MyObject *obj1, MyObject *obj2) {
int index1 = [nameIndexes indexOfObject:obj1.name];
int index2 = [nameIndexes indexOfObject:obj2.name];
return [[NSNumber numberWithInt:index1] compare:[NSNumber numberWithInt:index2]];
}];
Not 100% certain what you are asking but this will sort take the set of names and turn it into a sorted array sorted based on the index of the names in a second array.
After edit
Edit... ok, so your edit completely changed the question. Anyway, from the edit you can just do...
NSArray *result = [[set allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:"name" ascending:YES]]];
This will take the set and return a sorted array sorted by the name property of the objects in alphabetical order.

Related

NSArray of NSDictionaries - filtering by dictionary value and return unique array object

So suppose I have an NSArray populated with hundreds of NSDictionary objects.
All dictionary objects have a value for the key name but these values names may appear more than once in different objects.
I need to be able to filter this NSArray to only return one object per unique name attribute (whichever object, first or last, I don't care).
This is how far I've got but obviously my filtered array contains all objects rather than only unique ones.
I'm thinking there must be a way to tell the predicate to limit its results to only one / first match?
NSArray *allObjects = ... // This is my array of NSDictionaries
NSArray *uniqueNames = [allObjects valueForKeyPath:#"#distinctUnionOfObjects.name"];
NSArray *filtered = [allObjects filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"(self.name IN %#)", uniqueNames]];
Thanks!
NSMutableDictionary *uniqueObjects = [NSMutableDictionary dictionaryWithCapacity:allObjects.count];
for (NSDictionary *object in allObjects) {
[uniqueObjects setObject:object forKey:object[#"name"]];
}

reassigning a bool value to NSArray

i have an NSArray with bool values:
NSArray* boolResults = [super foo:values];
how can i change the value in cell 0?
i tried the following:
boolResults[0] = #NO;
this results in an error: Expected method to write array element not found on object of type 'NSArray *'
and also this:
BOOL* b = &[[array objectAtIndex:i] boolValue];
got the following error: Address expression must be an lvalue or a function designator
i don't wish to convert this NSArray to NSMutableArray in order to set this value, is there a normal way to do this?
Thanks
If the array isn't mutable, then you can't change that value. The solutions are two:
Make the array mutable;
Let the array contain mutable objects.
Since you don't want to use a mutable array, I'll make you an example with the second solution. Since there isn't a mutable number in the standard framework, I'll wrap it into NSMutableData. The example supposes that you have an array with a single object, with value #YES, and you want to change it to #NO:
NSNumber* number= #YES;
NSMutableData* data=[[NSMutableData alloc]initWithData: [NSKeyedArchiver archivedDataWithRootObject: number]];
NSArray* array= #[data]; // Now you have an array with a single value
// You want to change the first value to #NO:
number= #NO;
[array[0] setData: [NSKeyedArchiver archivedDataWithRootObject: number]];
No. NSArrays are immutable. You could reassign your pointer to the array with a modified NSArray.
NSArray *anArray = [super foo:values]
NSMutableArray *mutableCopy = [anArray mutableCopy];
// change your mutable copy and then reassign
anArray = [mutableCopy copy];
And just like NSArray, NSNumbers are also immutable, so something like [anArray[0] setBoolValue:NO] does not exist.

Create Instance variables at runtime

I want to create instance variables dynamically at runtime, and I want to add these variables to a category. The number of the instance variables may change based on the configuration/properties file which I am using for defining them.
Any ideas??
Use Associative References - this is tricky, but that is the mechanism invented specifically for your use case.
Here is an example from the link above: first, you define a reference and add it to your object using objc_setAssociatedObject; then you can retrieve the value back by calling objc_getAssociatedObject.
static char overviewKey;
NSArray *array = [[NSArray alloc] initWithObjects:# "One", #"Two", #"Three", nil];
NSString *overview = [[NSString alloc] initWithFormat:#"%#", #"First three numbers"];
objc_setAssociatedObject (
array,
&overviewKey,
overview,
OBJC_ASSOCIATION_RETAIN
);
[overview release];
NSString *associatedObject = (NSString *) objc_getAssociatedObject (array, &overviewKey);
NSLog(#"associatedObject: %#", associatedObject);
objc_setAssociatedObject (
array,
&overviewKey,
nil,
OBJC_ASSOCIATION_ASSIGN
);
[array release];
I'd be inclined to just use a NSMutableDictionary (see NSMutableDictionary Class Reference). Thus, you would have an ivar:
NSMutableDictionary *dictionary;
You'd then initialize it:
dictionary = [NSMutableDictionary dictionary];
You can then save values to it dynamically in code, e.g.:
dictionary[#"name"] = #"Rob";
dictionary[#"age"] = #29;
// etc.
Or, if you are reading from a file and don't know what the names of the keys are going to be, you can do this programmatically, e.g.:
NSString *key = ... // your app will read the name of the field from the text file
id value = ... // your app will read the value of the field from the text file
dictionary[key] = value; // this saves that value for that key in the dictionary
And if you're using an older version of Xcode (before 4.5), the syntax is:
[dictionary setObject:value forKey:key];
Depends on exactly what you want to do, the question is vague but if you want to have several objects or several integers or so on, arrays are the way to go. Say you have a plist with a list of 100 numbers. You can do something sort of like this:
NSArray * array = [NSArray arrayWithContentsOfFile:filePath];
// filePath is the path to the plist file with all of the numbers stored in it as an array
That will give you an array of NSNumbers, you can then turn that into an array of just ints if you want like this;
int intArray [[array count]];
for (int i = 0; i < [array count]; i++) {
intArray[i] = [((NSNumber *)[array objectAtIndex:i]) intValue];
}
Whenever you want to get an integer from a certain position, lets say you want to look at the 5th integer, you would do this:
int myNewInt = intArray[4];
// intArray[0] is the first position so [4] would be the fifth
Just look into using a plist for pulling data, it will them be really easy to create arrays of custom objects or variables in your code by parsing the plist.

NSMutableArray contains Objects

I have to check whether an NSMutableArray contains an object multiple times (for e.g. the array contains 1,2,3,1,4), I want to know how many times 1 is present in the array. I am aware of containsObject: but how to use it for this kind of check?
NSCountedSet may help as you want to track how many times a duplicate value occurs.
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSCountedSet_Class/Reference/Reference.html#//apple_ref/occ/cl/NSCountedSet
A quick way would be to convert it to an NSSet and then back to an array. NSSets cannot contain duplicates. Alternatively copy the values one by one into a new array using a loop, and each time check that the new array does not contain a copy of the object before adding it.
It depends on your object types, but if they can be used as keys for an NSDictionary, I would create an NSMutableDictionary that points to NSNumber objects containing counts for each object instance. Something like:
NSArray *array = whatever;
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:array.count];
for ( id obj in array )
{
NSNumber *number = [d objectForKey:obj];
if ( number == nil )
{
[d setObject:[NSNumber numberWithInt:1] forKey:obj];
}
else
{
[d setObject:[NSNumber numberWithInt:([number intValue]+1) forKey:obj];
}
}
At the end of this code, you are left with an NSDictionary where the keys are your original objects and the values are NSNumbers that contain the number of times that key exists in the original.

Sort Array of NSString By Custom Method

How would I go about sorting an array of NSString Objects by a custom method. For example I have a method
-(int)calculateValue:(NSString *)aString
I would like to sort an array by descending order based on the returned value from this method. So for example I have an array
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:#"Apple", #"Bee", #"Super", nil];
Now if I call calculateValue for each of those strings it might return values such as.
"Apple" = 15, "Bee" = 21, and "Super" = 3. Now I'm trying to sort that array based on the returned value for each NSString from the calculateValue method. So then the sorted array would like like
[Bee, Apple, Super]
See -sortedArrayUsingSelector:. You'll pass in a selector like #selector(myComparisonMethod:). Your comparison method should return an NSComparisonResult like NSOrderedAscending, NSOrderedDescending, or NSOrderedSame.