在objective-c中对服装尺寸进行排序

时间:2012-10-04 20:02:09

标签: objective-c nsarray

我有一个NSArray,其值为XS,S,M,L,XL,XXL,为​​随机顺序。

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

我看了这个代码的起点,但我没有运气:

Sort a list by reference C#

3 个答案:

答案 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方法阻止。