在多个属性上对 NSArray 自定义对象进行排序 [英] Sort NSArray custom object on multiple properties

查看:59
本文介绍了在多个属性上对 NSArray 自定义对象进行排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有多个属性的自定义对象.

I have a custom object with multiple properties.

一个属性是一个类型,例如一个枚举:A、B、C 等

One property is a Type, for example an enum: A, B, C etc

这些都有日期.

@property (assign) CustomType customType;
@property (nonatomic, strong) NSDate *startDate;
...

typedef NS_ENUM(NSInteger, CustomType) {
    A,
    B,
    C
};

我想首先放置所有类型为C"的对象,然后按日期 DESC 对其余对象进行排序.

I would like to put all objects of type 'C' first then order the rest by their Date DESC.

实现这一目标的最佳方法是什么?

What is the best way to achieve this?

我尝试添加多个 sortDescriptor,但我只想要顶部的 C 对象,然后其余按日期排序,这按日期对每个分组进行排序.

I've tried adding multiple sortDescriptors but I only want C objects at the top, then the rest ordered by date, this orders each grouping by date.

NSSortDescriptor *sortDescriptor1 =[[NSSortDescriptor alloc] initWithKey:@"customType" ascending:NO];
NSSortDescriptor *sortDescriptor2 =[[NSSortDescriptor alloc] initWithKey:@"startDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil];
NSArray *sortedObjects = [_items sortedArrayUsingDescriptors:sortDescriptors];

示例

+-------------------------+
| C | 2017-08-16 12:48:53 |
| C | 2017-08-15 12:46:53 |
| B | 2017-08-16 12:48:53 |
| B | 2017-08-14 12:43:53 |
| A | 2017-08-15 12:46:53 |
| A | 2017-08-14 12:31:53 |
+-------------------------+

愿意

+-------------------------+
| C | 2017-08-16 12:48:53 |
| C | 2017-08-15 12:46:53 |
| A | 2017-08-16 12:48:53 |
| B | 2017-08-15 12:46:53 |
| A | 2017-08-14 12:43:53 |
| B | 2017-08-14 12:31:53 |
+-------------------------+

我也可以先决定我想要哪种 customType,所以我可能希望 B 位于顶部,然后其余的只是按日期?

Also can I decide which customType I would like first, so I might want B to be at the top, then the rest just by date?

将数组分成两组会更容易吗,所有的 C 然后其余的.对每个子组进行排序,然后将它们重新组合在一起?

Would it be easier to split the array into two groups, of ALL C then the rest. Sort each sub group, then join them back together?

然后我可以在下面的谓词中选择我想要的顶级组:

I can then choose which top group I want in the below predicate:

NSPredicate *pred1 = [NSPredicate predicateWithFormat:@"customType == %ld", C];
NSPredicate *pred2 = [NSPredicate predicateWithFormat:@"customType != %ld", C];
NSArray *top = [_items filteredArrayUsingPredicate:pred1];
NSArray *bottom = [_items filteredArrayUsingPredicate:pred2];

NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"startDate" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, nil];
NSArray *sortedTop = [top sortedArrayUsingDescriptors:sortDescriptors];
NSArray *sortedBottom = [bottom sortedArrayUsingDescriptors:sortDescriptors];

//NSArray *items = [NSArray arrayWithObjects:sortedTop, sortedBottom, nil];

NSArray *newArray = @[];
newArray = [newArray arrayByAddingObjectsFromArray:sortedTop];
newArray = [newArray arrayByAddingObjectsFromArray:sortedBottom];

_items = [newArray mutableCopy];

<小时>

按日期排序https://stackoverflow.com/a/6084944/2895831

NSLog(@"nodeEventArray == %@", nodeEventArray);
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"startDate" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
NSArray *sortedEventArray = [nodeEventArray sortedArrayUsingDescriptors:sortDescriptors];
NSLog(@"sortedEventArray == %@", sortedEventArray);

<小时>

过去,我按给定的属性对数组进行分组,并对该单个属性使用自定义排序.


In the past I've grouped an array by a given property and used a custom sort on that single property.

如何在 NSArray 上使用自定义排序

@property (nonatomic, strong) NSString *level;

NSArray *levels = [array valueForKeyPath:@"@distinctUnionOfObjects.level"];

NSArray *levelsSortOrder = @[@"Beginner", @"Basic", @"Intermediate", @"Expert", @"Advanced", @"Developer", @"Seminar"];

NSArray *sortedArray = [levels sortedArrayUsingComparator: ^(id obj1, id obj2){
    NSUInteger index1 = [levelsSortOrder indexOfObject: obj1];
    NSUInteger index2 = [levelsSortOrder indexOfObject: obj2];
    NSComparisonResult ret = NSOrderedSame;
    if (index1 < index2)
    {
        ret = NSOrderedAscending;
    }
    else if (index1 > index2)
    {
        ret = NSOrderedDescending;
    }
    return ret;
}];

推荐答案

我喜欢 sortedArrayUsingComparator:,我认为你不能用其他方法做你想做的事.

I like sortedArrayUsingComparator:, and I don't think you can do what you want with the others methods.

sortedArrayUsingComparator: 给出了非常大的排序操作.其背后的逻辑是:比较它们之间的两个对象(obj1obj2).您决定这两篇论文的排序.它将遍历整个数组,并通过将每个对象两两比较,将得到排序结果.因此,在块中,您必须明确定义为什么一个对象优先"于另一个对象.这里CustomType就是其中之一,并且优先于startDate.所以让我们按照这个顺序来做.

sortedArrayUsingComparator: gives really large actions on how sort. The logic behind it is: Compare two objects between them (obj1 and obj2). You decide the sort on theses two. It will iterate through the whole array, and by comparing each objects two by two it will have the sorted result. So in the block, you have to explicit exactly what define why is an object "prioritized" against the other one. Here CustomType is one of them, and is prioritized before startDate. So let's do it in this order.

然后实现:

NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator: ^(CustomClass *obj1, CustomClass2 *obj2){ 
    CustomType type1 = [obj1 customType]; 
    CustomType type2 = [obj2 customType]; 
    if (type1 == C && type2 == C)
    {
        return [[obj1 startDate] compare:[obj2 startDate]];
    }
    else if (type1 == C && type2 != C) 
    {
        return NSOrderedAscending;
    }
    else if (type1 != C && type2 == C)
    {
        return NSOrderedDescending;
    }
    else //if (type1 != C && type2 != C)
    {
        return [[obj1 startDate] compare:[obj2 startDate]];
    }
}];

稍加重构:

NSArray *sortedArray = [unsortedArray sortedArrayUsingComparator: ^(CustomClass *obj1, CustomClass2 *obj2){ 
    CustomType type1 = [obj1 customType]; 
    CustomType type2 = [obj2 customType]; 
    if (type1 == C && type2 != C) 
    {
        return NSOrderedAscending;
    }
    else if (type1 != C && type2 == C)
    {
        return NSOrderedDescending;
    }
    else //Either (type1 == C && type2 == C) OR (type1 != C && type2 != C)
    {
        //return [[obj1 startDate] compare:[obj2 startDate]];
        return [[obj2 startDate] compare:[obj1 startDate]];
    }
}];

请注意,NSOrderedAscendingNSOrderedDescending 可能必须颠倒,我不知道该使用哪个,我总是测试.

Note that NSOrderedAscending and NSOrderedDescending may have to be reversed, I never know which one to use, I always test.

我将两个块中的 id 替换为您的 CustomClass,因为您已经知道您拥有的对象类别.这避免了一行强制转换:CustomType type1 = [(CustomClass *)obj1 customType];

I replace id in both blocks with your CustomClass because you already know the class of objects you have. This avoids a line of cast: CustomType type1 = [(CustomClass *)obj1 customType];

这篇关于在多个属性上对 NSArray 自定义对象进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆