如何根据属性从数组中创建NSSet
个对象。
e.g。数组中存在对象数组,每个对象都具有对type
属性的强引用,并且每种类型都出现多次出现。如何将其转换为NSSet
持有每种类型的单个对象。
答案 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
属性。