【问题标题】:Obj-C - Sorting tableview data by date(s) in string?Obj-C - 按字符串中的日期对表格视图数据进行排序?
【发布时间】:2021-07-07 17:58:50
【问题描述】:

我有一个数组 (self.filteredArray),它返回其中键 scheduledate 包含今天的日期(在本例中为 2021 年 4 月 12 日)的字典。控制台返回以下内容:

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

        }
    )

【问题讨论】:

  • 我们不是建议您使用模型,而不是NSDictionary吗?即,自定义NSObject 带有一个名为NSString 的属性title,一个NSDate 属性(如果需要,也可以是一个NSArray,如果你可以有多个日期的话),如果你有两个日期,逻辑是什么?你想复制 NSDictionary?使用最新日期进行比较?较早的那个?最“接近”今天?
  • 我不使用 NSObject 是有原因的。我只是想让我上面的代码在我的 tableView 中从最早到最晚安排今天的时间。如果 obj1[scheduleddate] 或 obj2[scheduleddate] 字符串中列出了多个日期,我似乎无法访问“今天的时间”。 @Larme
  • 您想要排序或过滤。目前还不清楚。目标输出是什么?如果你也有{ "node_title" = "Michael Levy with old date"; scheduleddate = "Apr 01 2021 11:00 AM, Apr 03 2021 5:00 PM";} 它应该出现吗?在哪里?而且你不应该对numberOfRowsInSection:进行排序,你会调用该方法太多次,它应该只排序一次。
  • 啊@Larme 看到上面我的目标 nsdictionary 输出!将其添加到问题中。我基本上只是想删除我的字符串中不包含“Apr 12 2021”的任何字符串。为冗长的解释道歉,哈哈。同意,只是意识到我应该把它移到 numberOfRowsInSection 之外!感谢您的帮助:)

标签: ios objective-c sorting uitableview


【解决方案1】:

好的,您想按 scheduleddate 键中的日期值对字典数组进行排序。

如果scheduleddate 有时包含多个日期,如果您可以假设正确的日期是最后一个日期会更简单。如果做不到这一点,请执行以下操作:

编写一个函数dateTodayFromString(_:),它接受一个字符串并返回一个日期。

让它使用NSString 方法containsString 来确定它是否包含逗号。如果没有,只需应用日期格式化程序并返回结果日期。

如果是,请使用componentsSeparatedByString: ", " 将多个日期分开。使用您的DateFormatter 将每个日期转换为Date,循环遍历日期数组并使用Calendar 函数isDateInToday 查找当前日期。如果找到,则返回。

重写您的排序函数以调用您的dateTodayFromString(_:) 函数以从每个数组条目中的字符串中获取日期。

请注意,如果您的数组包含超过 ≈100 个条目,您应该真正将数组转换为可变字典数组,并在尝试对其进行排序之前将所有这些日期字符串转换为 Date 对象。将日期字符串转换为每次比较的日期会使排序过程变慢(我似乎记得在我测试它时,在一个中等大小的数组上花费了大约 12 倍的时间,但我必须回去测试它。)

【讨论】:

    【解决方案2】:

    您的问题与排序无关。这是关于过滤和映射的。

    为什么? 您需要过滤,因为您想拒绝某些值。 您需要“映射”,因为您想更改一些值。

    所以我们做了一个手动过滤,因为我们想同时映射,即:一个简单的 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);
    

    【讨论】:

    • 你是神。哈哈。太感谢了。我会尝试听从你的建议,走 NSObject 路线。
    猜你喜欢
    • 1970-01-01
    • 2018-07-07
    • 2010-12-27
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 2021-12-18
    • 2016-09-03
    • 1970-01-01
    相关资源
    最近更新 更多