问题
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?
回答1:
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];
}];
回答2:
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.
回答3:
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
来源:https://stackoverflow.com/questions/8303523/sorting-an-nsarray-of-strings-not-string-based