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 ^^

2
  • Where are you getting these strings from? Commented Aug 20, 2015 at 8:50
  • The user enters them in another viewController, that passes the data to the tableViewController to display Commented Aug 20, 2015 at 13:35

4 Answers 4

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).

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

Comments

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.

Comments

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];

1 Comment

Brilliant Solution!Thanks. It saves a lot of time :)
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?

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.