Сортировка NSDictionary с несколькими ограничениями - PullRequest
2 голосов
/ 01 октября 2010

У меня есть коллекция NSDictionary, ключом которой является уникальный идентификатор, а значением является массив с двумя разными объектами (FruitClass, ProductClass), и я хотел бы сгруппировать коллекцию так, чтобы она сортировалась сначала по ProductClass.productName, а затем по FruitClass. имя элемента.

Таким образом, окончательный список будет выглядеть примерно так:

{apple, butter}
{apple, pie}
{banana, daiquiri}
{banana, smoothie}
{melon, zinger}

, где первый элемент - это элемент экземпляра FruitClass, а второй - элемент экземпляра ProductClass.

Какой лучший способ сделать это? Большинство примеров, с которыми я сталкивался, сделаны на одном ключе. Как вы делаете это с NSDictionary, который имеет 2 различных типа объектов?

Просмотр ключей NSDictionary'sSortedByValueUsingSelector,

- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator

У меня сложилось впечатление, что вы создадите метод сравнения для типа класса объекта значения. Так что, для сортировки по нескольким полям, придется ли мне прибегать к созданию нового типа объекта, CombinedClass, который содержит FruitClass & ProductClass, и реализации «сравнения», чтобы это произошло?

FruitClass:
{
    NSString *itemName;
}
@end
@interface ProductClass
{
    NSString *productName;
}
@end

Ответы [ 3 ]

1 голос
/ 01 октября 2010

Если существует структура данных, состоящая только из одного фрукта и только одного продукта, то массив на самом деле не является хорошим вариантом.Вы можете использовать другой класс и предоставить компаратор compare::

@interface ComboClass : NSObject
{
    FruitClass *fruit;
    ProductClass *product;
}

@property(nonatomic,retain) FruitClass *fruit;
@property(nonatomic,retain) ProductClass *product;

- initWithFruit:(FruitClass *)f andProduct:(ProductClass *) p;

@end


@implementation ComboClass

@synthesize fruit;
@synthesize product;

- (void) dealloc
{
    [fruit release];
    [product release];
    [super dealloc];
}

- initWithFruit:(FruitClass *)f andProduct:(ProductClass *) p
{
    self = [super init];
    if (!self) return nil;

    self.fruit = f;   // some recommend against accessor usage in -init methods
    self.product = p;

    return self;
}

- (NSComparisonResult) compare:(id) another
{
    NSComparisonResult result = [self.fruit.itemName compare:another.fruit.itemName];
    if (result == NSOrderedSame)
        return [self.product.productName compare:another.product.productName];
    else
        return result;
}

@end

В качестве альтернативы, вы можете использовать NSDictionary с парами ключ-значение product и fruit (так чтов конечном итоге со словарями внутри словаря).Класс NSSortDescriptor можно использовать для сортировки массивов по значениям путей ключей, поэтому это может быть еще один вариант для изучения.

0 голосов
/ 01 октября 2010

Вы можете добавить категорию в NSArray, которая будет выполнять сравнение, и вам не нужно будет создавать другой класс.

@interface NSArray ( MySortCategory )
    - (NSComparisonResult)customCompareToArray:(NSArray *)arrayToCompare;
@end

Реализация должна быть довольно простой на основе вашего описания.

Редактировать Я был немного раздражен, что это было отмечено без комментариев, поэтому я сделал полную реализацию, чтобы убедиться, что это будет работать.Это немного отличается от вашего образца, но та же идея.

FruitsAndProducts.h

@interface Fruit : NSObject
{
    NSString *itemName;
}

@property(nonatomic, copy)NSString *itemName;

@end

@interface Product : NSObject
{
    NSString *productName;
}

@property(nonatomic, copy)NSString *productName;

@end

FruitsAndProducts.m

#import "FruitsAndProducts.h"

@implementation Fruit

@synthesize itemName;

@end


@implementation Product

@synthesize productName;

@end

NSArray + MyCustomSort.h

@interface NSArray (MyCustomSort)
- (NSComparisonResult)customCompareToArray:(NSArray *)arrayToCompare;
@end

NSArray + MyCustomSort.m

#import "NSArray+MyCustomSort.h"

#import "FruitsAndProducts.h"

@implementation NSArray (MyCustomSort)

- (NSComparisonResult)customCompareToArray:(NSArray *)arrayToCompare
{
    // This sorts by product first, then fruit.
    Product *myProduct = [self objectAtIndex:0];
    Product *productToCompare = [arrayToCompare objectAtIndex:0];

    NSComparisonResult result = [myProduct.productName caseInsensitiveCompare:productToCompare.productName];
    if (result != NSOrderedSame) {
        return result;
    }

    Fruit *myFruit = [self objectAtIndex:1];
    Fruit *fruitToCompare = [arrayToCompare objectAtIndex:1];

    return [myFruit.itemName caseInsensitiveCompare:fruitToCompare.itemName];
}


@end

Вот оно в действии

// Create some fruit.
Fruit *apple = [[[Fruit alloc] init] autorelease];
apple.itemName = @"apple";
Fruit *banana = [[[Fruit alloc] init] autorelease];
banana.itemName = @"banana";
Fruit *melon = [[[Fruit alloc] init] autorelease];
melon.itemName = @"melon";

// Create some products
Product *butter = [[[Product alloc] init] autorelease];
butter.productName = @"butter";
Product *pie = [[[Product alloc] init] autorelease];
pie.productName = @"pie";
Product *zinger = [[[Product alloc] init] autorelease];
zinger.productName = @"zinger";

// create the dictionary. The array has the product first, then the fruit.
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys:[NSArray arrayWithObjects:zinger, banana, nil], @"zinger banana", [NSArray arrayWithObjects:butter, apple, nil], @"butter apple", [NSArray arrayWithObjects:pie, melon, nil], @"pie melon", nil];

NSArray *sortedKeys = [myDict keysSortedByValueUsingSelector:@selector(customCompareToArray:)];

for (id key in sortedKeys) {
    NSLog(@"key: %@", key);
}
0 голосов
/ 01 октября 2010

Ваш компаратор может работать с тем, что вы ему набрасываете ... вы можете заставить его обрабатывать два аргумента s как объект NSArray s , если этоэто то, что вам нужно.Когда вы помещаете массивы в качестве значений в свой словарь, тогда просто используйте их - нет необходимости в другом классе.

Если вы хотите построить новый класс в любом случае (возможно, по соображениям дизайна) - используйте его, но этоздесь не нужно «делать».

Редактировать: вычеркнуть, чтобы прояснить, что дан только один аргумент - поскольку другой является объектом, к которому вызывается селектор.Использование NSArray потребует расширения класса, пользовательский класс намного чище.

...