Obj-C - 按字符串中的日期对表视图数据进行排序?
Obj-C - Sorting tableview data by date(s) in string?
我有一个 returns 字典数组 (self.filteredArray),其中键 scheduleddate 包含今天的日期(在本例中为 2021 年 4 月 12 日)。控制台 returns 以下内容:
2021-04-12 09:14:30.942723-0700 [58012:24654705] The filtered please (
{
"node_title" = "Elisa Carmichael";
scheduleddate = "Apr 12 2021 1:00 PM";
},
{
"node_title" = "Michael Levy";
scheduleddate = "Apr 10 2021 11:00 AM, Apr 12 2021 5:00 PM";
},
{
"node_title" = "Trisha Johnson";
scheduleddate = "Apr 12 2021 6:00 PM";
}
)
我的目标是按照安排的时间将这些人安排在“今天”表格视图中。当 scheduledate 仅包含一个日期和时间时,以下代码可以完美运行,即。 2021 年 4 月 12 日 1:00 下午。然而,有些人在同一个预定日期字符串中安排了多个日期和时间(在上面,Michael Levy),这打破了排序顺序。
有没有办法让我编写以下代码,使最终数组 (self.sortedByTime) 仅按包含今天日期的“,”分隔值排列返回的个体?
我希望这是有道理的。谢谢。
ViewController.m
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.todaytableView) {
self.sortedByTime = [self.filteredArray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2)
{
int i;
for (i = 0; i < [self.filteredArray count]; i++) {
}
NSDate *date1 = [dateFormatter dateFromString:obj1[@"scheduleddate"]];
NSDate *date2 = [dateFormatter dateFromString:obj2[@"scheduleddate"]];
return [date1 compare:date2];
}];
self.finalTimes = [[NSMutableArray alloc]initWithArray:self.sortedByTime];
return [self.finalTimes count];
}
我的目标输出:
2021-04-12 09:14:30.942723-0700 [58012:24654705] The filtered please (
{
"node_title" = "Elisa Carmichael";
scheduleddate = "Apr 12 2021 1:00 PM";
},
{
"node_title" = "Michael Levy";
scheduleddate = "Apr 12 2021 5:00 PM";
},
{
"node_title" = "Trisha Johnson";
scheduleddate = "Apr 12 2021 6:00 PM";
}
)
好的,您想按 scheduleddate
键中的日期值对字典数组进行排序。
如果 scheduleddate
有时包含多个日期,如果您可以假设正确的日期是最后一个日期会更简单。如果失败,请执行以下操作:
编写一个函数 dateTodayFromString(_:)
接受字符串和 return 日期。
让它使用 NSString
方法 containsString
来确定它是否包含逗号。如果没有,只需应用日期格式化程序和 return 结果日期。
如果是,请使用 componentsSeparatedByString: ", "
将多个日期分开。使用 DateFormatter
将每个转换为 Date
,遍历日期数组并使用 Calendar
函数 isDateInToday
查找当天的日期。如果它找到一个,return 那。
重写排序函数以调用 dateTodayFromString(_:)
函数从每个数组条目中的字符串中获取日期。
请注意,如果您的数组包含超过 ≈100 个条目,您应该真正将数组转换为可变字典数组,并在尝试对其进行排序之前将所有这些日期字符串转换为 Date 对象。将日期字符串转换为每次比较的日期会使排序过程变慢很多(我似乎记得当我测试它时,在中等大小的数组上花费了大约 12 倍的时间,但我必须回去测试它。)
您的问题与排序无关。这是关于过滤和映射。
为什么?
您需要过滤,因为您想要拒绝某些值。
你需要“映射”,因为你想改变一些值。
所以我们做了一个手动过滤器,因为我们想同时映射,即:一个简单的 for 循环,对于每个元素,我们检查日期字符串中是否有一个“今天”的候选日期,我们保留第一个找到的。
NSArray *array = @[@{@"node_title": @"Elisa Carmichael",
@"scheduleddate": @"Apr 12 2021 1:00 PM"},
@{@"node_title": @"Michael Levy",
@"scheduleddate": @"Apr 10 2021 11:00 AM, Apr 12 2021 5:00 PM"},
@{@"node_title": @"Trisha Johnson",
@"scheduleddate":@"Apr 12 2021 6:00 PM"}];
NSMutableArray *mappedAndfiltered = [[NSMutableArray alloc] init];
for (NSDictionary *aDict in array) {
NSString *scheduledDatesString = aDict[@"scheduleddate"];
NSArray *dates = [scheduledDatesString componentsSeparatedByString:@","];
NSUInteger candidateIndex = [dates indexOfObjectPassingTest:^BOOL(NSString * _Nonnull dateStr, NSUInteger idx, BOOL * _Nonnull stop) {
return [dateStr containsString:@"Apr 12 2021"]; //That's for the tests, but in fact, use your NSDateFormatter and check if the NSDate is today, I was just lazy to redo a formatter for your sample and check if it's within today
}];
if (candidateIndex != NSNotFound) {
[mappedAndfiltered addObject:@{@"node_title": aDict[@"node_title"],
@"scheduleddate": dates[candidateIndex]}];
}
}
NSLog(@"mappedAndfiltered: %@", mappedAndfiltered);
//现在,用你现在的方法重新排序
但是:
我强烈建议使用自定义模型 NSObject
。
因为你一直在操作 NSString,它们应该是 NSDate
并且你一直在它们之间进行转换以排序、编辑数据等。字符串表示应该只为用户保留,而不是开发人员。否则容易出错
使用快速模型:
@interface MyModel: NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) NSArray *dates;
@property (nonatomic, strong) NSDate *dateWithinToday;
-(id)initWithDict:(NSDictionary *)dict;
-(id)initWithTitle:(NSString *)title dateStrings:(NSArray *)commaSeparatedDateStrings;
@end
@implementation MyModel
-(id)initWithDict:(NSDictionary *)dict {
if (self == [self initWithTitle:dict[@"node_title"] dateStrings:[dict[@"scheduleddate"] componentsSeparatedByString:@","]]) {
}
return self;
}
-(id)initWithTitle:(NSString *)title dateStrings:(NSArray *)commaSeparatedDateStrings {
if (self == [super init]) {
_title = title;
NSMutableArray *datesArray = [[NSMutableArray alloc] init];
for (NSString *aDateStr in commaSeparatedDateStrings) {
//Use a "single formatter"
[datesArray addObject:[__dateFormatter dateFromString:aDateStr]];
}
_dates = datesArray;
NSUInteger index = [datesArray indexOfObjectPassingTest:^BOOL(NSDate * _Nonnull date, NSUInteger idx, BOOL * _Nonnull stop) {
return [[NSCalendar currentCalendar] isDateInToday:date];
}];
if (index != NSNotFound) {
_dateWithinToday = datesArray[index];
}
}
return self;
}
-(NSString *)description {
return [NSString stringWithFormat: @"%@ - title: %@ - todaydate: %@ - all dates: %@" , [super description], _title, _dateWithinToday, _dates];
}
@end
并在使用中:
NSMutableArray *arrayOfObjects = [[NSMutableArray alloc] init];
for (NSDictionary *aDict in array) {
[arrayOfObjects addObject:[[MyModel alloc] initWithDict:aDict]];
}
NSPredicate *todayPredicate = [NSPredicate predicateWithBlock:^BOOL(MyModel * _Nullable aModel, NSDictionary<NSString *,id> * _Nullable bindings) {
return [aModel dateWithinToday] != nil;
}];
NSArray *filtered = [arrayOfObjects filteredArrayUsingPredicate:todayPredicate];
NSArray *sorted = [filtered sortedArrayUsingComparator:^NSComparisonResult(MyModel * _Nonnull obj1, MyModel * _Nonnull obj2) {
return [[obj1 dateWithinToday] compare:[obj2 dateWithinToday]];
}];
NSLog(@"sorted: %@", sorted);
我有一个 returns 字典数组 (self.filteredArray),其中键 scheduleddate 包含今天的日期(在本例中为 2021 年 4 月 12 日)。控制台 returns 以下内容:
2021-04-12 09:14:30.942723-0700 [58012:24654705] The filtered please (
{
"node_title" = "Elisa Carmichael";
scheduleddate = "Apr 12 2021 1:00 PM";
},
{
"node_title" = "Michael Levy";
scheduleddate = "Apr 10 2021 11:00 AM, Apr 12 2021 5:00 PM";
},
{
"node_title" = "Trisha Johnson";
scheduleddate = "Apr 12 2021 6:00 PM";
}
)
我的目标是按照安排的时间将这些人安排在“今天”表格视图中。当 scheduledate 仅包含一个日期和时间时,以下代码可以完美运行,即。 2021 年 4 月 12 日 1:00 下午。然而,有些人在同一个预定日期字符串中安排了多个日期和时间(在上面,Michael Levy),这打破了排序顺序。
有没有办法让我编写以下代码,使最终数组 (self.sortedByTime) 仅按包含今天日期的“,”分隔值排列返回的个体?
我希望这是有道理的。谢谢。
ViewController.m
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.todaytableView) {
self.sortedByTime = [self.filteredArray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2)
{
int i;
for (i = 0; i < [self.filteredArray count]; i++) {
}
NSDate *date1 = [dateFormatter dateFromString:obj1[@"scheduleddate"]];
NSDate *date2 = [dateFormatter dateFromString:obj2[@"scheduleddate"]];
return [date1 compare:date2];
}];
self.finalTimes = [[NSMutableArray alloc]initWithArray:self.sortedByTime];
return [self.finalTimes count];
}
我的目标输出:
2021-04-12 09:14:30.942723-0700 [58012:24654705] The filtered please (
{
"node_title" = "Elisa Carmichael";
scheduleddate = "Apr 12 2021 1:00 PM";
},
{
"node_title" = "Michael Levy";
scheduleddate = "Apr 12 2021 5:00 PM";
},
{
"node_title" = "Trisha Johnson";
scheduleddate = "Apr 12 2021 6:00 PM";
}
)
好的,您想按 scheduleddate
键中的日期值对字典数组进行排序。
如果 scheduleddate
有时包含多个日期,如果您可以假设正确的日期是最后一个日期会更简单。如果失败,请执行以下操作:
编写一个函数 dateTodayFromString(_:)
接受字符串和 return 日期。
让它使用 NSString
方法 containsString
来确定它是否包含逗号。如果没有,只需应用日期格式化程序和 return 结果日期。
如果是,请使用 componentsSeparatedByString: ", "
将多个日期分开。使用 DateFormatter
将每个转换为 Date
,遍历日期数组并使用 Calendar
函数 isDateInToday
查找当天的日期。如果它找到一个,return 那。
重写排序函数以调用 dateTodayFromString(_:)
函数从每个数组条目中的字符串中获取日期。
请注意,如果您的数组包含超过 ≈100 个条目,您应该真正将数组转换为可变字典数组,并在尝试对其进行排序之前将所有这些日期字符串转换为 Date 对象。将日期字符串转换为每次比较的日期会使排序过程变慢很多(我似乎记得当我测试它时,在中等大小的数组上花费了大约 12 倍的时间,但我必须回去测试它。)
您的问题与排序无关。这是关于过滤和映射。
为什么? 您需要过滤,因为您想要拒绝某些值。 你需要“映射”,因为你想改变一些值。
所以我们做了一个手动过滤器,因为我们想同时映射,即:一个简单的 for 循环,对于每个元素,我们检查日期字符串中是否有一个“今天”的候选日期,我们保留第一个找到的。
NSArray *array = @[@{@"node_title": @"Elisa Carmichael",
@"scheduleddate": @"Apr 12 2021 1:00 PM"},
@{@"node_title": @"Michael Levy",
@"scheduleddate": @"Apr 10 2021 11:00 AM, Apr 12 2021 5:00 PM"},
@{@"node_title": @"Trisha Johnson",
@"scheduleddate":@"Apr 12 2021 6:00 PM"}];
NSMutableArray *mappedAndfiltered = [[NSMutableArray alloc] init];
for (NSDictionary *aDict in array) {
NSString *scheduledDatesString = aDict[@"scheduleddate"];
NSArray *dates = [scheduledDatesString componentsSeparatedByString:@","];
NSUInteger candidateIndex = [dates indexOfObjectPassingTest:^BOOL(NSString * _Nonnull dateStr, NSUInteger idx, BOOL * _Nonnull stop) {
return [dateStr containsString:@"Apr 12 2021"]; //That's for the tests, but in fact, use your NSDateFormatter and check if the NSDate is today, I was just lazy to redo a formatter for your sample and check if it's within today
}];
if (candidateIndex != NSNotFound) {
[mappedAndfiltered addObject:@{@"node_title": aDict[@"node_title"],
@"scheduleddate": dates[candidateIndex]}];
}
}
NSLog(@"mappedAndfiltered: %@", mappedAndfiltered);
//现在,用你现在的方法重新排序
但是:
我强烈建议使用自定义模型 NSObject
。
因为你一直在操作 NSString,它们应该是 NSDate
并且你一直在它们之间进行转换以排序、编辑数据等。字符串表示应该只为用户保留,而不是开发人员。否则容易出错
使用快速模型:
@interface MyModel: NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, strong) NSArray *dates;
@property (nonatomic, strong) NSDate *dateWithinToday;
-(id)initWithDict:(NSDictionary *)dict;
-(id)initWithTitle:(NSString *)title dateStrings:(NSArray *)commaSeparatedDateStrings;
@end
@implementation MyModel
-(id)initWithDict:(NSDictionary *)dict {
if (self == [self initWithTitle:dict[@"node_title"] dateStrings:[dict[@"scheduleddate"] componentsSeparatedByString:@","]]) {
}
return self;
}
-(id)initWithTitle:(NSString *)title dateStrings:(NSArray *)commaSeparatedDateStrings {
if (self == [super init]) {
_title = title;
NSMutableArray *datesArray = [[NSMutableArray alloc] init];
for (NSString *aDateStr in commaSeparatedDateStrings) {
//Use a "single formatter"
[datesArray addObject:[__dateFormatter dateFromString:aDateStr]];
}
_dates = datesArray;
NSUInteger index = [datesArray indexOfObjectPassingTest:^BOOL(NSDate * _Nonnull date, NSUInteger idx, BOOL * _Nonnull stop) {
return [[NSCalendar currentCalendar] isDateInToday:date];
}];
if (index != NSNotFound) {
_dateWithinToday = datesArray[index];
}
}
return self;
}
-(NSString *)description {
return [NSString stringWithFormat: @"%@ - title: %@ - todaydate: %@ - all dates: %@" , [super description], _title, _dateWithinToday, _dates];
}
@end
并在使用中:
NSMutableArray *arrayOfObjects = [[NSMutableArray alloc] init];
for (NSDictionary *aDict in array) {
[arrayOfObjects addObject:[[MyModel alloc] initWithDict:aDict]];
}
NSPredicate *todayPredicate = [NSPredicate predicateWithBlock:^BOOL(MyModel * _Nullable aModel, NSDictionary<NSString *,id> * _Nullable bindings) {
return [aModel dateWithinToday] != nil;
}];
NSArray *filtered = [arrayOfObjects filteredArrayUsingPredicate:todayPredicate];
NSArray *sorted = [filtered sortedArrayUsingComparator:^NSComparisonResult(MyModel * _Nonnull obj1, MyModel * _Nonnull obj2) {
return [[obj1 dateWithinToday] compare:[obj2 dateWithinToday]];
}];
NSLog(@"sorted: %@", sorted);