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?
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];
}];
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.
maybe you can sort your strings where "xx s" was replaced by "z", "xs" was replaced by "v" and "xl" replaced with "b" and "xx l" with "a". q
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.