3

我有一个 NSArray,其值 XS、S、M、L、XL、XXL 以随机顺序排列。

我将如何在 Objective-C 中正确排序?

我查看了这段代码作为起点,但我的运气为零:

通过引用 C# 对列表进行排序

4

3 回答 3

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使用快速排序,那么我们正在查看 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);
于 2012-10-04T22:04:54.757 回答
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您正在排序的数组进行比较,如果它们相等,则不要打扰迭代。

于 2012-10-04T20:32:07.860 回答
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);
   }

这将打印到控制台:S M M L L XL

如您所见,enum我没有使用 C# 解决方案中提到的方法,而是使用包含的 NSDictionnary,NSNumber因此我可以直接使用块compare中的方法comparison

于 2012-10-04T20:25:49.917 回答