我有一个 NSArray,其值 XS、S、M、L、XL、XXL 以随机顺序排列。
我将如何在 Objective-C 中正确排序?
我查看了这段代码作为起点,但我的运气为零:
我有一个 NSArray,其值 XS、S、M、L、XL、XXL 以随机顺序排列。
我将如何在 Objective-C 中正确排序?
我查看了这段代码作为起点,但我的运气为零:
为此,您可以创建一个包含正确顺序的值的参考数组,然后根据每个元素出现在参考数组中的索引对输入数组进行排序。到白衣:
NSArray *reference = @[ @"XS", @"S", @"M", @"L", @"XL", @"XXL" ];
NSArray *inputArray = @[ @"S", @"M", @"L", @"L", @"M", @"S", @"XXL", @"S" ];
NSArray *sortedArray = [inputArray sortedArrayUsingComparator:
^NSComparisonResult(id a, id b) {
NSUInteger aindex = [reference indexOfObject:a];
NSUInteger bindex = [reference indexOfObject:b];
if (aindex > bindex)
return (NSComparisonResult)NSOrderedDescending;
if (aindex < bindex)
return (NSComparisonResult)NSOrderedAscending;
return (NSComparisonResult)NSOrderedSame;
}];
NSLog(@"%@", sortedArray);
这行得通,但它的缺点是调用indexOfObject:
的频率比我们想要的多得多。如果我们假设sortedArrayUsingComparator
使用快速排序,那么我们正在查看 O(N*logN) 比较,每个比较调用indexOfObject:
两次。indexOfObject:
依次在 O(N) 时间内运行。那么总的来说,不好。
有几种方法可以改善这一点。例如,您可以使用decorate-sort-undecorate成语。在这里,您预先计算数组元素的排序键(在本例中为参考数组索引),用它们装饰数组元素,使用它们进行排序,然后将它们剥离。
在这种情况下,将值转换为引用数组中的索引(而不是修饰它们),然后再转换回来(而不是不修饰)会更容易。不过同样的想法。这是它的外观:
// First get the indices
NSMutableArray *indices = [NSMutableArray arrayWithCapacity:[inputArray count]];
for (id elem in inputArray) {
[indices addObject:@([reference indexOfObject:elem])];
}
// Then sort the list of indices
[indices sortUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"self"
ascending:YES]]];
// Finally, translate indices back to source elements
NSMutableArray *results = [NSMutableArray arrayWithCapacity:[inputArray count]];
for (NSNumber *index in indices) {
[results addObject:reference[[index unsignedIntegerValue]]];
}
NSLog(@"%@", results);
您可以解决它的另一种方法是将引用数组改为引用字典,并将值(“XS”、“S”等)映射到它们的排序顺序(0、1...)。这实际上与我的第一个解决方案相同,但参考数组索引已预先计算并存储在字典中。与indexOfObject:
在 O(N) 时间内运行的 不同,通过其键查找字典值在 O(1) 时间内运行。
在对象字面量出现之前,这将是难以想象的丑陋,但现在它非常优雅。对于小型参考集,这将是我的首选。
NSDictionary *reference = @{
@"XS": @0,
@"S": @1,
@"M": @2,
@"L": @3,
@"XL": @4,
@"XXL": @5
};
NSArray *inputArray = @[ @"S", @"M", @"L", @"L", @"M", @"S", @"XXL", @"S" ];
NSArray *sortedArray = [inputArray sortedArrayUsingComparator:
^NSComparisonResult(id a, id b) {
return [reference[a] compare:reference[b]];
}];
NSLog(@"%@", sortedArray);
如果您创建一个有序集以充当“参考”订单,那么您可以使用该NSMutableSet
方法intersectSet:
从您的数组中创建一个有序列表:
编辑 David Rönnqvist刚刚提出了一个很好的观点。需要检查相同“大小”的多个实例。
//This is my "reference" set, declared only once in my class
NSOrderedSet *reference = [NSOrderedSet orderedSetWithObjects:@"XS",@"S",@"M",@"L",@"XL", nil];
//This is the array I'm trying to sort, which may or may not contain all the sizes
NSArray *randomArray = [NSArray arrayWithObjects:@"XL", @"XS", @"M", @"XS", nil];
//Create a mutable ordered set from my reference
NSMutableOrderedSet *ordered = [NSMutableOrderedSet orderedSetWithOrderedSet:reference];
//Interset with the array
[ordered intersectSet:[NSSet setWithArray:randomArray]];
//Look for multiple instances of the same size
NSMutableArray *result = [NSMutableArray array];
for (NSString *sortedSize in ordered){
for (NSString *randomSize in randomArray){
if ([randomSize isEqualToString:sortedSize]){
[result addObject:randomSize];
}
}
}
我从上面得到的结果是一个数组,其中包含:
@"XS", @"XS", @"M", @"XL"
如果您要创建一个执行此操作的方法,您还可以将计数与ordered
您正在排序的数组进行比较,如果它们相等,则不要打扰迭代。
我认为一个简单的方法是使用 sortedArrayUsingComparator 方法:
- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmpt
您的代码将如下所示:
NSArray * randomArray = [NSArray arrayWithObjects: @"S", @"L", @"M", @"L", @"XL", @"M", nil];
NSMutableDictionary *dictionary = [[ NSMutableDictionary alloc]
init];
[ dictionary setObject: [NSNumber numberWithInt:1] forKey:@"S"];
[ dictionary setObject: [NSNumber numberWithInt:2] forKey:@"M"];
[ dictionary setObject: [NSNumber numberWithInt:3] forKey:@"L"];
[ dictionary setObject: [NSNumber numberWithInt:4] forKey:@"XL"];
NSArray *sortedArray = [randomArray sortedArrayUsingComparator:
^(id obj1, id obj2) {
NSNumber *value1 = [dictionary objectForKey:obj1];
NSNumber *value2 = [dictionary objectForKey:obj2];
return [value1 compare:value2];
}];
for (NSString *item in sortedArray)
{
NSLog(@"%@", item);
}
这将打印到控制台:S M M L L XL
如您所见,enum
我没有使用 C# 解决方案中提到的方法,而是使用包含的 NSDictionnary,NSNumber
因此我可以直接使用块compare
中的方法comparison
。