我有一个NSArray,其值为XS,S,M,L,XL,XXL,为随机顺序。
我如何在Objective-C中正确排序?
我看了这个代码的起点,但我没有运气:
答案 0 :(得分:1)
如果您创建一个有序集合作为“参考”订单,则可以使用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
的计数与您正在排序的数组进行比较,如果它们相等则不要为迭代而烦恼。
答案 1 :(得分:1)
您可以通过创建一个引用数组来实现此目的,该数组包含正确顺序的值,然后根据每个元素在引用数组中出现的索引对输入数组进行排序。致白:
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
使用quicksort,那么我们会查看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 ...)。这实际上与我的第一个解决方案相同,但预先计算并存储在字典中的参考数组索引。与在O(N)时间内运行的indexOfObject:
不同,通过其键在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);
答案 2 :(得分:0)
我认为一种简单的方法是使用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);
}
这将打印到控制台: 小号 中号 中号 大号 大号 XL
如您所见,我没有使用C#解决方案中提到的enum
而是使用包含NSNumber
的NSDictionnary,因此我可以在compare
中直接使用comparison
方法阻止。