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属性ごとに 1 つのオブジェクトしかありません。この手順では、後のオブジェクトが優先されて保持されることに注意してください。元の配列の順序が重要な場合は、ディクショナリを作成する前に逆にします。

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

私はLinqtoObjectiveCと呼ばれる単純なライブラリを作成しました。これは、この種の問題をはるかに簡単に解決できるようにするメソッドのコレクションです。あなたの場合、Linq-to-ObjectiveCの個別のメソッドが必要です。

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

これは、各アイテムが個別のtypeプロパティを持つセットを返します。

于 2013-03-08T20:16:14.140 に答える
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];

これは、配列内のオブジェクトのタイプに関係なく機能し、配列内の重複オブジェクトが 1 つだけ出現するように 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 に答える