iPhone - How to build a list of unique items - iphone

I want an array which contains only unique items. I know I could do this with an NSDictionary adding items with keys and then get allKeys. This would ensure that the NSArray contains only unique items, but I feel that this would be overkill and believe that there should be an easier way to do this, but cannot find one.

NSArray* uniqueArray = [[NSSet setWithArray:originalArray] allObjects];
Uniqueness is based on the isEqual: method.

Use NSSet or NSMutableSet for this. Keep in mind that uniqueness will be based on object address if you don't override the isEqual: method. Unless, of course, you are using classes that implement that method (NSNumber, NSValue, for example).

You can use NSSet for this

Related

NSArray - quick way to find index of object for know description

Hi i have NSArray of id objects.
And i know object description NSString.
how can i find object and avoid array enumeration?
p.s. i don't like to using NSDictionary, bcs it's do code more difficult
If this is a lookup you plan to perform more often and speed is an issue, you should probably not store the objects in a NSArray but instead in a NSDictionary to begin with, where the keys are the description strings of the objects and the values are the objects themselves. You can then use objectForKey: with the description string as argument, which is a O(1) lookup.
Try this one :
[myArray containsObject:yourObject];
Or you can filter it :
[myArray filterUsingPredicate:predicate];

Removing elements in NSMutableDictionary is deleting other dictionary

I'll try to be as much clear as possible:
I create 2 MutableDictionary
I add to both of them the same NSMutableArray object:
[self.myList setObject:tempC forKey:keyV];
[self.listFiltered setObject:tempC forKey:keyV];
In other part of the code, I want to empty one, so I do:
[self.listFiltered objectForKey:keyV] removeAllObjects];
The problem is that the objects are being removed in BOTH mutableDictionaries!
The same NSNSMutableArray is added to both dictionaries. It doesn't matter whether you access it through one dictionary or the other, you end up manipulating the same NSMutableArray instance.
To fix this, you need store different NSMutableArray instances in each dictionary. The easiest way to do this is through [NSMutableArray copy], which will do a shallow copy.
Lastly, naming dictionaries with names ending in list is a bad practice.
You need to copy the array to the other dictionary.
See here on how you can go about this.
Both objects are same... you only provide a pointer to that mutablearray to both the dictionary so when you delete in one the other also gets deleted .. what you need is to store copy of that array into your dictionary... hoping this helps.
you can add the array like this..(Seems to me you want a deep copy)
NSMutableArray *newArrayOne = [[NSMutableArray alloc] initWithArray:tempC copyItems:YES];
[self.myList setObject:newArrayOne forKey:keyV];
[newArrayOne release];
NSMutableArray *newArrayTwo = [[NSMutableArray alloc] initWithArray:tempC copyItems:YES];
[self.listFiltered setObject:newArrayTwo forKey:keyV];
[newArrayTwo release];
this way two different objects are stored in there.. this is not the most optimized code.. it is just to make you understand what actually is happening behind the scenes.

Accessing array/set of objects with keys

I want to be able to add objects to an NSArray and access them with Keys. Currently the way im doing it is creating a seperate NSDictionary of key-value pairs where the value is an integer number representing the index in my NSArray. This seems like an extra step to me.
If my understanding of NSDictionary is correct, only 'values' can be stored: a pointer to an object cannot.
Surely there must be an equivalent NSDictionary type function that allows objects to be stored and accessed with a key? I have looked through the documentation, but cant seem to find any answers, unless im missing something obvious.
NSDictionary is to store key value pairs. if you are adding key value pair after you created the dictioanry, use NSMutableDictionary class . example,
[dictionaryObject setObject:#"" forKey:#"abc"];
You can store objects in NSDictionary and can be accessed via keys...
In short, no.
An array (NSArray) is an ordered collection of references to objects, so simply said, an ordered collection of objects.
As opposed to dictionaries, which are unordered and values are accessed by keys.
You understanding of collections is probably wrong, you don't store values, but pointers (references).
The extra step is necessary if you need to store the references in an array, but in this case, you should consider using a dictionary. An option is to use keys that take care of the order.
For example :
[myDictionary objectForKey:#"1"];
could be an equivalent of :
[myArray objectAtIndex:1];
Thats wrong, you can store objects in a NSDictionary. Look at the method dictionaryWithObjects:forKeys: or dictionaryWithObjectsAndKeys:
I have no experience in Cocoa but looking at the documentation it seems like NSDictionary (or at least NSMutableDictionary) should handle your request (without you using NSArray).
I think I understand your problem. My suggestion for you is to use NSMutableArray and macros, like:
NSMutableArray *array=[[NSMutableArray alloc]init];
#define SOME_MACRO 0
id someObject;
[array insertObject:someObject atIndex:SOME_MACRO];
id getterObject=[array objectAtIndex:SOME_MACRO];
Of course define the macros in the header file.

How to use an object as a key in Objective-C

I would like to use a custom object as a key in a hash-like structure. I've tried using NS[Mutable]Dictionary but in order for my object to be a key it has to implement the NSCopying protocol. NSDictionary is sending a copy message to all of it's keys as far as I've read. I don't want to implement the protocol (my object is quite complex) nor do I want it to be copied. What are my options? Do I have any?
NSDictionary is toll-free bridged with CFDictionaryRef, but they actually differ in behavior when adding objects. Specifically, NSDictionary's -setObject:forKey: will copy the key, but CFDictionaryRef's CFDictionarySetValue() will not copy the key. This means that if you want to use non-copyable keys, you can use CFDictionarySetValue() instead to add it to the dictionary.
CFDictionarySetValue((CFMutableDictionaryRef)myDict, myKey, myValue);
This will still retain the key, but it won't copy it. And you can use the normal NSDictionary methods for everything else.
Do you need the NSDictionary to retain the object? If not, you can turn it into an NSValue and use that as the key:
NSValue *value = [NSValue valueWithNonretainedObject:yourCustomObject];
[dictionary setObject:someObject forKey:value];
This can get a bit messy but is in alternative to implementing NSCopying.
You can roll your own dictionary. Not really that hard.
Another option is to use a surrogate object, containing a pointer to "the" object. The surrogate would implement the hash and either copy or reference the fields to be compared for isEqual. It could do a basic sanity check to assure the compared fields have not been changed when it's referenced.
You could just do this:
- (id)copyWithZone:(NSZone *)zone {
return [self retain];
}

Most efficient way to find out if an object is already in an NSMutableArray?

I just want to know if an object is in an array or not.
So I can use:
- (BOOL)containsObject:(id)anObj
But it would send -isEqual to every object in the array. Bad when there are thousands of them.
And then there is:
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject
which seems to only compare the memory addresses. I think this is faster. But a bit nasty to use, of course. One would have to check for NSNotFound.
Is -indexOfObjectIdenticalTo really the best option?
if you really need this often, you can create an instance method by category:
#interface NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object;
#end
#implementation NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object {
return NSNotFound != [self indexOfObjectIdenticalTo:arg];
}
#end
or these's also CFArrayContainsValue.
a simple function would also suffice.
But a bit nasty to use
Why? It seems to me that
if ([array indexOfObjectIdenticalTo: foo] != NSNotFound)
{
// do what you need
}
is not much more nasty than
if ([array containsObject: foo])
{
// do what you need
}
Which one you choose depends on what equality semantics you use. You almost certainly want to use -containsObject: for arrays containing NSStrings or NSNumbers because -isEqual: gives the correct equality semantics.
Both methods, by the way are O(n) which is where the real performance problem is. If the idea of a linear search is a problem, consider a different data structure e.g. based on NSDictionary.
As per your explaining and comparison indexOfObjectIdenticalTo seems me the first choice to use..
Here is one more SO post ..
indexOfObject vs. indexOfObjectIdenticalTo
If possible (for example if sorting order is irrelevant) you could use an NSDictionary instead, with your object as keys and values of [NSNull null]. Note that the objects get copied when used as keys ! Your objects would need to implement the - (NSUInteger)hash method.
Also see the excellent NSArray or NSSet, NSDictionary or NSMapTable analysis from Matt Gallagher.