如何NSSet
根据属性从数组创建对象。
例如,对象数组,每个对象都具有对type
属性的强引用,并且数组中存在每种类型的多次出现。这怎么能变成NSSet
持有每种类型的单个对象。
如何NSSet
根据属性从数组创建对象。
例如,对象数组,每个对象都具有对type
属性的强引用,并且数组中存在每种类型的多次出现。这怎么能变成NSSet
持有每种类型的单个对象。
NSSet *distinctSet = [NSSet setWithArray:[array valueForKeyPath:@"@distinctUnionOfObjects.property"]];
字典本质上已经具有此功能。它的键是一个集合,因此您可以创建字典来保存对象,并以您感兴趣的任何属性为键:
[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
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];
}
}
你会使用:
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 输出中获得所需的信息。
我创建了一个简单的库,称为Linq to ObjectiveC,它是使此类问题更容易解决的方法的集合。在您的情况下,您需要Linq-to-ObjectiveC distinct方法:
NSSet* dictionary = [NSSet setWithArray:[sourceArray distinct:^id(id item) {
return [item type] ;
}]];
这将返回一个集合,其中每个项目都有不同的type
属性。