5

So i have an array that i retrieve from a web service in no particular order

example:

0 => x large, 
1 => large, 
2 => XX large, 
3 => small,
4 => medium, 
5 => x small

I need to sort them: firstly based on specific - which could be reverse alphabetic:

small
medium
large

Secondly i need to sort them based on their 'x' counter parts:

x small
small
medium
large
x large
xx large

I know i can do this with brute force string matching but i would really like a suggestion on how to do this tidily, perhaps a regex or something more elegant?

3 Answers 3

9

Use NSComparator block syntax. Something like

NSArray * sizes = [NSArray arrayWithObjects:  @"x small",@"small",@"medium",@"large",@"x large", nil];

NSArray *sortedBySizes =[array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    if ([sizes indexOfObject:[obj1 size]]> [sizes indexOfObject:[obj2 size]])
        return (NSComparisonResult)NSOrderedAscending;
    if ([sizes indexOfObject:[obj1 size]]< [sizes indexOfObject:[obj2 size]])
        return (NSComparisonResult)NSOrderedDescending;
    return (NSComparisonResult)NSOrderedSame;
}];

In the second approach I added a mapping between the numbers send by the web server and the x-sizes. Now [obj size]; is suppose to return a NSNumber object.

NSArray * sizesStrings = [NSArray arrayWithObjects:  @"x small",@"small",
                                                     @"medium",@"large",
                                                     @"x large",@"xx large", 
                                                     nil];
NSArray * sizesNumbers = [NSArray arrayWithObjects:[NSNumber numberWithInt:5],
                                                   [NSNumber numberWithInt:3],
                                                   [NSNumber numberWithInt:4],
                                                   [NSNumber numberWithInt:1],
                                                   [NSNumber numberWithInt:0],
                                                   [NSNumber numberWithInt:2], 
                                                   nil];

NSDictionary *sizes = [NSDictionary dictionaryWithObjects:sizesStrings 
                                                   forKeys:sizesNumbers];

NSArray *sortedBySizes = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    NSString *sizeObj1String = [sizes objectForKey:[obj1 size]];
    NSString *sizeObj2String = [sizes objectForKey:[obj1 size]];

    int i1 = [sizesStrings indexOfObject:sizeObj1String];
    int i2 = [sizesStrings indexOfObject:sizeObj2String];

    if (i1 > i2)
        return (NSComparisonResult)NSOrderedAscending;
    if (i2 > i1)
        return (NSComparisonResult)NSOrderedDescending;
    return (NSComparisonResult)NSOrderedSame;
}];

The second task of the question — the grouping into small, medium, large — could be done like this:

NSDictionary *groups = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSMutableArray array],[NSMutableArray array],[NSMutableArray array], nil] 
                                    forKeys:[NSArray arrayWithObjects:@"small",@"medium",@"large",nil]
                        ];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    int i = [[obj size] intValue];
    if (i == 5 || i == 3) 
        [[groups objectForKey:@"small"] addObject:obj];
    else if (i == 2 || i == 0 || i == 1)
        [[groups objectForKey:@"large"] addObject:obj];
    else
        [[groups objectForKey:@"medium"] addObject:obj];

}];
Sign up to request clarification or add additional context in comments.

3 Comments

Thats awesome, i think i just popped a breaker though i've never seen this sort of code. I'll hack at it and get it working in mine.
these codes uses Blocks, an addition apple published in iOS4. Be sure, that you understand them, as they are getting more and more important and popular. i.e. several 3rd party Networking frameworks uses them. and they are important for apple new concurrency framework grand central dispatch. A Guide to Blocks
yep, this is awesome, i got it working. my "sizes" array is getting larger and larger, i wish the "size" box wasn't an open field!
3

First, add a category to NSString for sanity's sake

@implementation NSString (NSStringContainsCategory)

- (BOOL)contains:(NSString*)string;
{
    if(IsEmpty(string)) {
        return NO;
    }

    NSRange range = [self rangeOfString:string options:NSCaseInsensitiveSearch];

    if (range.location != NSNotFound) {
        return YES;
    }

    return NO;
}

@end

Then,

NSMutableArray* sortMe = [NSMutableArray arrayWithArray:theArrayYouWantToSort];

NSComparator smlComparator = ^NSComparisonResult(id string1, id string2) {
    // 1 = small, 2 = medium, 3 = large        
    NSNumber* string1Number = [NSNumber numberWithInt:0];
    NSNumber* string2Number = [NSNumber numberWithInt:0];

    if([string1 contains:@"large"]) {
        string1Number = [NSNumber numberWithInt:3];
    } else if([string1 contains:@"medium"]) {
        string1Number = [NSNumber numberWithInt:2];
    } else if([string1 contains:@"small"]) {
        string1Number = [NSNumber numberWithInt:1];
    }

    if([string2 contains:@"large"]) {
        string2Number = [NSNumber numberWithInt:3];
    } else if([string2 contains:@"medium"]) {
        string2Number = [NSNumber numberWithInt:2];
    } else if([string2 contains:@"small"]) {
        string2Number = [NSNumber numberWithInt:1];
    }

    NSComparisonResult compareSml = [string1Number compare:string2Number];

    if(compareSml == 0) {
        // if they are the same size, just use normal string comparison to sort x xx xxx etc
        return [string1 compare:string2];
    }
    return compareSml;
};

[sortMe sortUsingComparator:smlComparator];

I wouldn't call it elegant, but it's the simplest answer I could think of. You may want to reverse the ordering to suit your needs - just apply negative to comparison result. Comment if this doesn't work out, and I'll give it another look.

2 Comments

large = 3, medium = 2, small = 3? I think it should be 3,2,1.
+1 for cleverness, ALTHOUGH I think it is not the best design, if this compare methods are added to every NSString object, though It most probably is just needed in one specific place — when the server response is parsed.
0

maybe you can sort your strings where "xx s" was replaced by "z", "x s" was replaced by "v" and "x l" replaced with "b" and "xx l" with "a". q

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.