【问题标题】:Search NSArray using NSDate range使用 NSDate 范围搜索 NSArray
【发布时间】:2012-12-13 19:46:06
【问题描述】:

我有一个 NSArray,其中包含以下名称和日期对。注意:日期总是在我的自定义数组的索引 1 中

MyCustomArray: 
(
"Toms Bday"
"2012-01-10"
)
(
"Jesscia Bday"
"2012-01-27"
)
(
"Jills Bday"
"2012-03-03"
)
(
"Joes Bday"
"2012-04-15"
)

我的数组中有数百个名称日期对。因此,对于给定的 StartDate = "2012-01-01" 和 endDate = "2012-01-31" 我只想获得以下记录。我该怎么做?

(
    "Toms Bday"
    "2012-01-10"
    )
    (
    "Jesscia Bday"
    "2012-01-27"
    )

我查看了这篇帖子Why can't NSDate be compared using < or >?,但仍然无法弄清楚。

【问题讨论】:

  • 所以这是一个数组数组,其中第一项是代表日期的NSString,对吧?

标签: iphone ios ipad nsarray nsdate


【解决方案1】:

考虑到您的日期格式非常简单,您可以将它们作为字符串进行比较,结果应该是正确的:

NSString *start = @"2012-01-01";
NSString *end = @"2012-01-31";

NSString *date = @"2012-01-10";

if ([start compare:date] == NSOrderedAscending &&
    [end compare:date] == NSOrderedDescending) {
    // Note: might be descending for start and ascending for end, i'm not 100% sure, try both

    // valid date
}

【讨论】:

  • campare 是 NSDate 的一种方法,所以 start,end 和 date 必须是 NSDate 格式,谢谢
  • 要将字符串转换为日期需要做一些工作,但您没有展示如何过滤原始数组以产生所需的结果。我会说这是一个相当草率和不完整的答案,甚至无法编译。
  • 非常感谢并感谢@JayD 指出我必须将日期转换为 NSDate 对象。这是一个完美的小解决方案
  • 很高兴您发现这很有用。我仍然不知道这怎么可能是一个好的答案,因为它没有为您提供您所要求的解决方案,即根据自定义过滤器过滤 NSArray
  • @JayD compare:NSString 的一个完全有效的方法(参见here),它执行字典比较。大多数字符集都是这样构造的,因此字典顺序也适用于数字 - 至少在数字数量对应时。此外,可可甚至提供了一个选项来解释不同数量级的数字 (NSNumericSearch)。所以虽然我同意这个答案是走捷径,但实际上并没有错。
【解决方案2】:

假设entries 是您的NSArrayNSArrays 的NSStrings。

NSDateFormatter * formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd"];

NSString * start = @"2012-01-01";
NSDate * startDate = [formatter dateFromString:start];

NSString * end = @"2012-01-31";
NSDate * endDate = [formatter dateFromString:end];

NSIndexSet * indexes = [entries indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    NSString * dateString = obj[1]; // retrieve the date string
    NSDate * date = [formatter dateFromString:dateString];

    return !([date compare:startDate] == NSOrderedAscending ||
             [date compare:endDate] == NSOrderedDescending);
}];

NSArray * results = [entries objectsAtIndexes:indexes];

我在这里所做的是过滤通过块定义的测试(在开始日期和结束日期之间)的索引,然后创建一个仅包含这些索引的数组。

在此之前,您显然需要使用NSDateFormatter 从字符串中获取日期。

我个人更喜欢块而不是谓词,因为我认为它们更易于阅读。

【讨论】:

    【解决方案3】:

    如果您可以自己决定数据结构(即,它们不是外部要求),那么也许您想考虑将内部数组(可以说是数据集的记录)转换为字典。

    使用字典存储记录的优势在于 Cocoa 框架提供了存储、过滤和通常连接数据所需的一切。

    所以请允许我提出如下设置:

    // For the purposes of this piece of code, a hard coded array of dictionaries: 
    NSArray *fullArray = @[
        @{@"desc": @"Toms Bday",    @"bday": [NSDate dateWithString:@"2012-01-10 00:00:00 +00:00"]},
        @{@"desc": @"Jesscia Bday", @"bday": [NSDate dateWithString:@"2012-01-27 00:00:00 +00:00"]}
    // etc...
    ];
    
    
    // The interval of NSDates that you want to filter
    NSDate *intervalBeginning = [NSDate dateWithString:@"2012-01-15 00:00:00 +00:00"];
    NSDate *intervalEnd       = [NSDate dateWithString:@"2012-01-31 23:59:59 +00:00"];
    
    // Find the relevant record(s):
    NSArray *filteredArray = [fullArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"bday >= %@  and bday <= %@", intervalBeginning, intervalEnd]];
    

    完成!

    【讨论】:

    • 您也可以过滤NSArray。无论如何,我同意使用 and NSDictionary 表示单个条目是更好的选择。
    • 谢谢。所有这些解决方案都很好,所以我给大家一个评价!
    【解决方案4】:

    感谢大家帮助我。这是我的 Kal-Calendar 项目中现在正在运行的代码。我希望这可以帮助任何可能对未来感兴趣的人。虽然其他回答这篇文章的人有更好的通用答案

    - (void)loadHolidaysFrom:(NSDate *)fromDate to:(NSDate *)toDate delegate:(id<KalDataSourceCallbacks>)delegate
    {
        NSLog(@"Fetching B-Days between %@ and %@...", fromDate, toDate);
    
        NSDateFormatter *fmt = [[[NSDateFormatter alloc] init] autorelease];
        [fmt setDateFormat:@"yyyy-MM-dd"];
    
    
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
        NSString *stringsPlistPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"birthdays.plist"];
    
        //READ IN
        NSMutableArray *arryData = [[NSMutableArray alloc] initWithObjects:nil];
        NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:stringsPlistPath];
    
    
    
        for (id key in dictionary) 
        {
            [arryData addObject:[dictionary objectForKey:key]];
        }
    
    
        for (int i=0; i<[arryData count]; i++)
        {
    
            NSMutableArray *bdayArray = [[NSMutableArray alloc] initWithArray:[arryData objectAtIndex:i]];
    
            NSString *nameStr = [bdayArray objectAtIndex:0];
            NSString *bdayStr = [bdayArray objectAtIndex:1];
    
            NSLog(@"nameStr:%@ ... bdayStr:%@ ...", nameStr,bdayStr);
    
    
            NSDate *BirthdayDate = [fmt dateFromString:bdayStr];
    
            if ([fromDate compare:BirthdayDate] == NSOrderedAscending &&
                [toDate compare:BirthdayDate] == NSOrderedDescending) 
            {
                // valid date
                //do something interesting here ... and it does!
            }
    
        }
    

    【讨论】:

    • 谢谢分享。我必须说,以 for 循环方式过滤数组并不是很优雅,即使它有效。 NSArray 有其特定的方法 - 基于谓词或块 - 来执行过滤器。我建议您查看@Monolo 的答案或我的答案。
    猜你喜欢
    • 1970-01-01
    • 2019-08-12
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多