tags:

views:

193

answers:

3

Hi all,

I have an array, which contains some duplicate entries. Firstly, is there any way to restrict duplicate entries when data getting inserted? secondly, if an array already having duplicate values than in some other way, we can retive only unique values from that array, i heard about NSSet aboout this, but i hv no idea how to use it.

any suggestion will be appreciated. regards

+5  A: 

If you've heard about NSSet, did you read the documentation? The API is similar to NSArray and very straightforward. Just like NSArray vs. NSMutableArray, you would use NSMutableSet if you need on the fly membership tests.

bbum
if (![AppDelegate.coffeeArray containsObject:coffeeObj.message]) { [AppDelegate.coffeeArray addObject:coffeeObj]; // does not contain. }is this a better way to restrict duplicate values????
shishir.bobby
Why is this getting so many upvotes? My answer **shows how to do this in code**
Brock Woolf
Likely because if someone knows how to use NSArray, they should be able to use NSSet. This is a pretty clear case of the OP not using the most basic of already available resources. (I'd give you a vote if your code worked, but `copy` of a set returns a set. Still; give a man a fish vs. teach a man to fish).
bbum
@bbum: I agree with you, but your answer took 10 seconds. Mine took 10 minutes to code, compile and check. It's the magnitude of effort vs reward. Believe it or not I knew how to use an `NSArray` for a long time, but not an `NSSet` (or even that it existed). Remember not everyone is as pro as they "should be". Anyway cheers for the vote @bbum.
Brock Woolf
I'll still give you that point if you fix the bug. :)
bbum
A bug in my code? I'll have a look
Brock Woolf
Haha oh, I forgot the reference gets passed the the assignee when you call `copy`. Updating...
Brock Woolf
+8  A: 

Don't use an NSSet.

You can only insert elements upon creation and cannot change the elements contained after you have created it.

If you want to add and remove objects on the fly, you can use an NSMutableSet.

Here is a demo of how to use it both NSSet and NSMutableSet, then converting the NSSet back to an NSArray (incase you want to do that):

- (void) NSMutableSetPrintTest
{
    NSMutableSet *mutableSet = [[NSMutableSet alloc] init];

    NSLog(@"Adding 5 objects (3 are duplicates) to NSMutableSet");
    NSString *firstString = @"Hello World";
    [mutableSet addObject:firstString];
    [mutableSet addObject:@"Hello World"];
    [mutableSet addObject:@"Goodbye World"];
    [mutableSet addObject:@"Goodbye World"];
    [mutableSet addObject:@"Goodbye World"];

    NSLog(@"NSMutableSet now contains %d objects:", [mutableSet count]);
    int j = 0;
    for (NSString *string in mutableSet) {
        NSLog(@"%d: %@ <%p>", j, string, string);
        j++;
    }

    NSLog(@"Now, if we are done adding and removing things (and only want to check what is in the Set) we should convert to an NSSet for increased performance.");
    NSSet *immutableSet = [NSSet setWithSet:mutableSet];

    NSLog(@"NSSet now contains %d objects:", [immutableSet count]);
    int i = 0;
    for (NSString *string in immutableSet) {
        NSLog(@"%d: %@ <%p>", i, string, string);
        i++;
    }

    [mutableSet release]; mutableSet = nil;

    NSLog(@"Now, if we are done with the sets, we can convert them back to an NSArray:");
    NSArray *array = [immutableSet allObjects];

    NSLog(@"NSArray contains %d objects", [array count]);
    int k = 0;
    for (NSString *string in array) {
        NSLog(@"%d: %@ <%p>", k, string, string);
        k++;
    }
}
Brock Woolf
ok great, i am getting unique values in mutableSet, than how to copy elements from this mutableSet to an another array ,say array b???
shishir.bobby
My code shows you how to do this already: `NSArray *b = [mutableSet copy];` PS: If my answer helped you, you can mark it as correct. Cheers.
Brock Woolf
Come on -- "How to copy elements from set to array??". **Look at the NSSet documentation.** It likely took longer to write that comment than it would to opt-double-click on NSSet and scroll down to the method list to see `allObjects`.
bbum
`[immutableSet copy]` does not return an array.....
bbum
@bbum correct, although *in this particular case* it'll still work thanks to duck typing (`-count` and `<NSFastEnumeration>` exist on both arrays and sets)
Dave DeLong
Good pickup guys. `[immutableSet allObjects]` returns an `NSArray` though. I've updated my answer. I removed the unnecessary `dealloc` as well.
Brock Woolf
@Dave It works by coincidence, obviously wasn't what was intended and will fail rather spectacularly with the first call to `objectAtIndex:`. This is one of the sharp edges created by Objective-C's lack of support for co-variant declarative argumentation. (Point added).
bbum
@bbum no disagreement from me. I just wanted to point out that despite the type mismatch, the code (as written) would still work (which of course you knew :) )
Dave DeLong
+5  A: 

NSMutableSet is probably the most logical thing to use.

However, be warned that a set does not maintain order of its elements (since a set, by definition, is unordered).

If that's a problem for you, then you have a couple of options:

  • duplicate set functionality with an NSMutableArray by invoking containsObject: before every call to addObject: (doable, but potentially slow, since arrays have O(n) search time)
  • use another object.

If you go with the second option, I would recommend taking a look at the excellent CHDataStructures framework, which has a subclass of NSMutableSet called CHOrderedSet, which is a set that maintains insertion order. (And since it's a subclass, it has the exact same API as an NSMutableSet)

Dave DeLong
A very technical (and correct) answer as always Dave. +1
Brock Woolf