根据属性从NSArray创建NSSet

时间:2013-03-07 02:52:52

标签: objective-c nsarray nsset

如何根据属性从数组中创建NSSet个对象。

e.g。数组中存在对象数组,每个对象都具有对type属性的强引用,并且每种类型都出现多次出现。如何将其转换为NSSet持有每种类型的单个对象。

5 个答案:

答案 0 :(得分:7)

NSSet *distinctSet = [NSSet setWithArray:[array valueForKeyPath:@"@distinctUnionOfObjects.property"]];

答案 1 :(得分:2)

字典本质上已经具有此功能。它的键是一个集合,所以你可以创建字典来保存对象,键入你感兴趣的任何属性:

[NSDictionary dictionaryWithObjects:arrayOfObjects 
                            forKeys:[arrayOfObjects valueForKey:theAttribute]];

如果您现在向字典询问allValues,则每个属性只有一个对象。我应该提一下,通过这个程序,后面的对象将更早地受到支持。如果原始数组的顺序很重要,请在创建字典之前将其反转。

您实际上无法将这些对象放入NSSet,因为NSSet将使用对象的isEqual:hash方法来确定它们是否应该是成员,而不是关键属性(当然,如果这是你自己的类,你可以覆盖这些方法,但这可能会干扰他们在其他集合中的行为)。

如果你真的觉得自己需要一套,你必须自己编写课程。你可以继承NSSet,但传统观点认为Cocoa集合的组合比子类化要容易得多。从本质上讲,你编写了一个涵盖你感兴趣的任何集合方法的类。这是一个(非常不完整且完全未经测试)的草图:

@interface KeyedMutableSet : NSObject

/* This selector is performed on any object which is added to the set.
 * If the result already exists, then the object is not added.
 */
@property (assign, nonatomic) SEL keySEL;

- (id)initWithKeySEL:(SEL)keySEL;

- (id)initWithArray:(NSArray *)initArray usingKeySEL:(SEL)keySEL;

- (void)addObject:(id)obj;

- (NSArray *)allObjects;

- (NSArray *)allKeys;

- (BOOL)containsObject:(id)obj;

- (NSUInteger)count;

-(void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block;

// And so on...

@end

#import "KeyedMutableSet.h"

@implementation KeyedMutableSet
{
    NSMutableArray * _objects;
    NSMutableSet * _keys;
}

- (id)initWithKeySEL:(SEL)keySEL
{
    return [self initWithArray:nil usingKeySEL:keySEL];
}

- (id)initWithArray:(NSArray *)initArray usingKeySEL:(SEL)keySEL
{
    self = [super init];
    if( !self ) return nil;

    _keySEL = keySEL;
    _objects = [NSMutableArray array];
    _keys = [NSMutableSet set];

    for( id obj in initArray ){
        [self addObject:obj];
    }

    return self;
}

- (void)addObject:(id)obj
{
    id objKey = [obj performSelector:[self keySEL]];
    if( ![keys containsObject:objKey] ){

        [_keys addObject:objKey];
        [_objects addObject:obj];
    }
}

- (NSArray *)allObjects
{
    return _objects;
}

- (NSArray *)allKeys
{
    return [_keys allObjects];
}

- (BOOL)containsObject:(id)obj
{
    return [_keys containsObject:[obj performSelector:[self keySEL]]];
}

- (NSUInteger)count
{
    return [_objects count];
}

- (NSString *)description
{
    return [_objects description];
}

-(void)enumerateObjectsUsingBlock:(void (^)(id, BOOL *))block
{
    for( id obj in _objects ){
        BOOL stop = NO;
        block(obj, &stop);
        if( stop ) break;
    }
}

@end

答案 2 :(得分:0)

你会使用:

NSSet* mySetWithUniqueItems= [NSSet setWithArray: yourArray];

无论数组中的对象类型如何,这都应该有效,并且只会在阵列中出现任何重复对象的情况下填充NSSet。

我希望这会有所帮助。

更新: 接下来最好的事情是:首先使用类名和对象属性的串联,然后使用上面的方法。

self.concatenatedArray=[NSMutableArray arrayWithCapacity:4];

for (TheClass* object in self.myArray)
    [self.concatenatedArray addObject:[NSString stringWithFormat:@"%@-%@",[object class], object.theProperty]];

self.mySet=[NSSet setWithArray:self.concatenatedArray];

我不确定您将使用NSSet输出,但您可以修改连接元素以获得NSSet输出中所需的信息。

答案 3 :(得分:0)

NSMutableSet* classes = [[NSMutableSet alloc] init];
NSMutableSet* actualSet = [[NSMutableSet alloc] init];

for(id object in array) {
    if([classes containsObject:[object class]] == NO) {
        [classes addObject:[object class]];
        [actualSet addObject:object];
    }        
}

答案 4 :(得分:0)

我创建了一个名为Linq to ObjectiveC的简单库,它是一组方法,使这类问题更容易解决。在您的情况下,您需要Linq-to-ObjectiveC distinct方法:

NSSet* dictionary = [NSSet setWithArray:[sourceArray distinct:^id(id item) {
    return [item type] ;
}]];

这将返回一个集合,其中每个项目都具有不同的type属性。