2

How can I sort an Array of strings that contains numbers AND characters? My tableView has this Data in it:

    - (void)viewDidLoad {
[super viewDidLoad];

self.tableData = [NSMutableArray array];

[self.tableData addObject:@"28 days"];
[self.tableData addObject:@"29 weeks"];
[self.tableData addObject:@"3 days"];
[self.tableData addObject:@"10 years"];
[self.tableData addObject:@"4 months"];
[self.tableData addObject:@"3 Weeks"];
[self.tableData addObject:@"27 Years"];
[self.tableData addObject:@"1 months"]; 
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithTitle:@"Sort" style:UIBarButtonItemStyleBordered target:self action:@selector(sort)];}

And I would like to sort it in a "natural" way, where the days come first, then the weeks, the months etc. and at the same time 2 days be before 5 days etc. Is that possible? or do I have to create separate arrays for weeks, months, years etc.?

This is the code I used:

- (void)sort {

NSSortDescriptor *sorter = [[NSSortDescriptor alloc]initWithKey:nil ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSArray *sortArray = [NSArray arrayWithObject:sorter];
NSArray *sortedArray = [self.tableData sortedArrayUsingDescriptors:sortArray];
[self.tableData removeAllObjects];
[self.tableData addObjectsFromArray:sortedArray];
[self.tableView reloadData];}

This doesn't solve the numerical problem though and somehow doesn't even sort the data in the right way ^^

Marwan
  • 388
  • 2
  • 11

4 Answers4

5

It would help if you created a custom class to hold your strings instead of putting them directly into the array. Then, this custom class, in addition to holding the strings, can hold a numerical value for the duration. This numerical value can be used to sort easily and can also assist you later when it comes to user selection and usage of the user choice.

Alternatively, you would use one of the sorting methods like sortedArrayUsingComparator: and supply code to check the textual and numerical content in the strings and work out the order (which isn't so easy).

Wain
  • 118,658
  • 15
  • 128
  • 151
2

If I understand you correctly you want to sort in a way that the shortest duration is first and the longest last. You will need to parse the strings yourself to get the number of days, weeks, months and years, calculate the total number of days from that and use this number as the sorting key in a custom sorting method.

Markus Dheus
  • 576
  • 2
  • 8
2

Assuming 1 week = 7 days, 1 month = 30 days, 1 year = 365 days – that means 5 weeks > 1 month – this might be a solution, although it's not quite correct regarding calendaric math.

It uses a dictionary as map table, separates the numeric value and the calendar unit and calculates a numeric value to be compared respectively.

  NSDictionary *mapTable = @{@"ays" : @1, @"eks" : @7, @"ths" : @30, @"ars" : @365};

  self.tableData = [NSMutableArray array];
  [self.tableData addObject:@"28 days"];
  [self.tableData addObject:@"29 weeks"];
  [self.tableData addObject:@"3 days"];
  [self.tableData addObject:@"10 years"];
  [self.tableData addObject:@"4 months"];
  [self.tableData addObject:@"3 Weeks"];
  [self.tableData addObject:@"27 Years"];
  [self.tableData addObject:@"1 months"];
  [self.tableData sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
    NSArray *components1 = [str1 componentsSeparatedByString:@" "];
    NSArray *components2 = [str2 componentsSeparatedByString:@" "];
    NSInteger faktor1 = [[mapTable objectForKey:[components1[1] substringFromIndex:[components1[1] length] - 3]] integerValue];
    NSInteger faktor2 = [[mapTable objectForKey:[components2[1] substringFromIndex:[components2[1] length] - 3]] integerValue];
    return ([components1[0] integerValue] * faktor1) > ([components2[0] integerValue] * faktor2);
  }];
  [self.tableView reloadData];
vadian
  • 274,689
  • 30
  • 353
  • 361
1

I believe an easier and more flexible solution would be to not store your objects as strings. Your objects seem to represent either dates or time intervals, which you could store in your array as either NSDate* or NSNumber* (of NSTimeInterval). In the case of NSDate, your sort becomes a simple:

  [dates sortedArrayUsingComparator:^NSComparisonResult(NSDate *dateA, NSDate *dateB) {
    return [dateA compare:dateB];
  }];

Displaying your data then becomes a simple NSDateComponents/NSDateFormatter problem: How do I break down an NSTimeInterval into year, months, days, hours, minutes and seconds on iPhone?

Community
  • 1
  • 1
Keller
  • 17,051
  • 8
  • 55
  • 72