8

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

例如,对象数组,每个对象都具有对type属性的强引用,并且数组中存在每种类型的多次出现。这怎么能变成NSSet持有每种类型的单个对象。

4

5 回答 5

7
NSSet *distinctSet = [NSSet setWithArray:[array valueForKeyPath:@"@distinctUnionOfObjects.property"]];
于 2013-03-07T03:05:34.683 回答
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
于 2013-03-07T20:41:30.480 回答
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];
    }        
}
于 2013-03-07T03:03:21.457 回答
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 输出中获得所需的信息。

于 2013-03-07T02:59:38.753 回答
0

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

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

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

于 2013-03-08T20:16:14.140 回答