使用多个约束对NSDictionary进行排序

时间:2010-09-30 20:55:58

标签: iphone sorting nsdictionary

我有一个NSDictionary集合,其键是一个唯一的id,value是一个包含两个不同对象的数组(FruitClass,ProductClass),我想将该集合分组,使其先由ProductClass.productName排序,然后由FruitClass排序。项目名称。

所以最终的列表看起来像是:

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

其中第一项是FruitClass实例项,第二项是ProductClass实例项。

这样做的最佳方法是什么?我遇到的大多数例子都是在一个键上完成的。如何使用具有2种不同对象类型的NSDictionary来完成它?

查看NSDictionary的keysSortedByValueUsingSelector,

- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator

我得到的印象是你会在值对象的类类型上创建'compare'方法。因此,对于多字段排序,我是否必须求助于创建一个新的对象类型,'CombinedClass',其中包含FruitClass& ProductClass并实施'比较'来实现这一目标?

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

3 个答案:

答案 0 :(得分:1)

如果数据结构只包含一个水果而且只包含一个产品,则数组不是一个好选择。您可以使用另一个类并提供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

或者,您可以使用带有productfruit键值对的NSDictionary(因此您最终会在字典中使用字典)。 NSSortDescriptor类可用于使用键路径的值对数组进行排序,因此可能是另一种探索选项。

答案 1 :(得分:-1)

你的比较器可以对你投掷的任何东西起作用......你可以将它的两个参数 s 视为NSArray对象 s ,如果这是你需要的。当您将数组作为值放入字典时,只需使用它们 - 不需要其他类。

如果你想建立一个新的课程(可能出于设计原因) - 去吧,但这不是“必须做的”。

编辑:删除以明确只给出一个参数 - 另一个是调用选择器的对象。使用NSArray需要类扩展,自定义类更清晰。

答案 2 :(得分:-1)

您可以向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);
}