Създайте NSSet от NSArray въз основа на свойството

Как се създава NSSet от обекти от масив въз основа на свойство.

напр. Масив от обекти, всеки със силна препратка към свойство type, и множество срещания от всеки тип съществуват в масива. Как може това да се превърне в NSSet, държащ един обект от всеки тип.


person some_id    schedule 07.03.2013    source източник
comment
Искате ли само първия екземпляр от всеки тип? Или произволен пример? Това всъщност не е очевидно картографиране от масив към набор.   -  person Seamus Campbell    schedule 07.03.2013
comment
Преминете през масива и добавете тези обекти в NSMutableSet.   -  person ZhangChn    schedule 07.03.2013
comment
Какъв е типът на type? Дали е низ, число, обект?   -  person CodaFi    schedule 07.03.2013
comment
Търся метод на библиотека за получаване на един обект от всяко появяване на стойност на свойство в масив от същия тип обект. Самият аз написах един, за да създам набора, но се чудех дали има оптимизиран метод на библиотеката.   -  person some_id    schedule 07.03.2013
comment
Имам свойство на низ на обект. И в масив, съдържащ обекти от този тип, искам да извлека един екземпляр за всяка различна стойност на свойството низ.   -  person some_id    schedule 07.03.2013
comment
@Helium3, моля, вижте коментара ми под въпроса ми, за да потвърдите. Търсите ли полученият NSSet да съхранява различните свойства (на един и същ обект) или да държи дублиращите се обекти, които имат различни свойства.   -  person Khaled Barazi    schedule 07.03.2013
comment
Да, напр. 4 обекта в масив с техните (NSString *) свойства на типа, зададени на @type1, @type2, @type1, @type3. Предаване на този масив в метод на библиотека за връщане на 3-те обекта, които съдържат трите уникални имена. Така че вместо да се връщат уникалните низове, трябва да се върнат обектите, които съдържат уникалните низове. Самият аз написах този метод, но се чудех дали има вече използван метод за оптимизирана библиотека.   -  person some_id    schedule 07.03.2013
comment
Краткият отговор на вашия въпрос е не. Няма библиотечен метод, който да прави това, което искате. Какъвто и метод да сте написали, е това, от което се нуждаете. Ако вашите обекти със същата стойност type върнаха YES от isEqual:, тогава всичко, което трябва да направите, е да създадете набор от масива и готово. Но тъй като това не изглежда да е така, трябва да напишете своя собствена персонализирана обработка.   -  person rmaddy    schedule 07.03.2013


Отговори (3)


Речникът по същество вече има тази функционалност. Неговите ключове са набор, така че можете да създадете речника, който да съдържа обектите, ключове с какъвто и да е атрибут, който ви интересува:

[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
person jscs    schedule 07.03.2013

Бихте използвали:

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.

person Khaled Barazi    schedule 07.03.2013
comment
Бих искал да получа набор от същия тип обект въз основа на уникални стойности на свойства. - person some_id; 07.03.2013
comment
@ReyGonzales, вярвам, че сложността тук е, че горният метод ще създаде NSSet с уникални обекти от масива. Helium се стреми да попълни NSSet с обекти, които са подобни на ниво обект, но всеки има различно свойство. - person Khaled Barazi; 07.03.2013
comment
Да, напр. 4 обекта в масив с техните (NSString *) свойства на типа, зададени на @type1, @type2, @type1, @type3. Предаване на този масив в метод на библиотека за връщане на 3-те обекта, които съдържат трите уникални имена. Така че вместо да се връщат уникалните низове, трябва да се върнат обектите, които съдържат уникалните низове. Самият аз написах този метод, но се чудех дали има вече използван оптимизиран библиотечен метод. - person some_id; 07.03.2013
comment
О, нямате нужда от това написано. Може би това трябва да се уточни във вашия въпрос. - person Rey Gonzales; 07.03.2013
comment
@Helium3, така че вашето притеснение най-вероятно тук не е, че NSSet ще съдържа дубликати на екземпляр от вашия клас (тъй като NSSet се грижи за това автоматично в моя отговор), а по-скоро, че искате да сте сигурни, че полученият NSSet не включва различни екземпляри, но които имат едно и също основно свойство? - person Khaled Barazi; 07.03.2013
comment
Моля, вижте актуализацията на моя отговор, можете да го направите с допълнителни няколко реда. - person Khaled Barazi; 07.03.2013

Създадох проста библиотека, наречена Linq към ObjectiveC, която е колекция от методи, които правят този вид проблемът е много по-лесен за решаване. Във вашия случай се нуждаете от метода Linq-to-ObjectiveC distinct:

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

Това връща набор, където всеки елемент има отделно свойство type.

person ColinE    schedule 08.03.2013