【问题标题】:Objective-c: Most efficient way to get the shortest range from a collection (NSArray) with rangesObjective-c:从具有范围的集合(NSArray)中获取最短范围的最有效方法
【发布时间】:2014-01-24 15:14:24
【问题描述】:

我有一个NSArray,其中包含多个对象,这些对象本身具有日期范围NSDate *startNSDate *end

我想要做的是遍历这个数组以找到基于当前date 的最短范围(在StartEnd 之间)。像这样的:

Date range Start 1 >----------< Date range End 1
    Date range Start 2 >-< Date range End 2
                        |
                   Current date

在上面的示例中,我想获取包含Date range start 2Date range End 2 的对象。

关于如何实现这一目标的任何想法和建议?

更新

基于当前日期,我的意思是当前日期应该在范围内。我不想要一个结束日期早于当前日期的范围,也不想要一个开始日期在未来的范围。

【问题讨论】:

  • 你的意思是提取数组中的当前日期??
  • 您能否说明当前日期是如何包含在计算中的? based on 不够具体。
  • @AlexBrown 我已经更新了我的问题。
  • 如果多个范围匹配你想要最短的?
  • @AlexBrown 嗯,好问题。如果我使用 NSDate 时间戳,你认为这可能吗?

标签: ios objective-c algorithm nsarray nspredicate


【解决方案1】:

有几个选项,具体取决于您希望结果的深度。第一种(也是最简单的)方法是按最小日期范围对数组进行排序:

array = array1 sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    double a = [obj1.endDate timeIntervalSinceDate:obj1.startDate];
    double b = [obj2.endDate timeIntervalSinceDate:obj2.startDate];

    if ( a < b ) {
        return (NSComparisonResult)NSOrderedAscending;
    } else if ( a > b ) {
        return (NSComparisonResult)NSOrderedDescending;
    } else {
        return (NSComparisonResult)NSOrderedSame;
    }
}

然后,当您需要检查包含今天日期的最短日期时,您可以从数组的开头开始并检查 startdate 是否在现在之前以及 enddate 是否在现在之后。第一个符合该条件的对象是您今天的最小范围。

NSDate *date = [NSDate date];
Object *foundObject;
for(Object *obj in array)
{
    if([obj.startDate timeIntervalSinceDate:date] <= 0 && [obj.endDate timeIntervalSinceDate:date] >= 0)
    {
        foundObject = obj;
        break;
    }
}

如果您想更深入地了解,可以使用谓词来获取围绕今天日期的所有对象的过滤数组。那么您可以获得最短的范围以及包含您要查找的日期的所有其他范围。

NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
    if([evaluatedObject.startDate timeIntervalSinceDate:date] <= 0 && [evaluatedObject.endDate timeIntervalSinceDate:date] >= 0)
    {
        return true;
    }
    return false;
}];
NSArray *array = [array1 filteredArrayUsingPredicate:pred];

【讨论】:

  • 首先将对象数组过滤为仅包含今天日期的对象(使用您的谓词)几乎肯定会更快,然后按日期的开始到结束范围对生成的过滤数组进行排序(如您在 sortedArrayUsingComparator 代码中所示)。排序是耗时的,对于较短的数组来说要快得多。对于这些对象的大型数组,将范围值添加到每个对象(作为 NSTimeInterval)而不是每次都计算它会更快,因为排序涉及多重比较。但是,对于相当小的数组,差异会很小。
  • @Duncan C 是的,但我的印象是数组将被排序一次,然后会进行多次调用以检查日期范围。如果这是一次性交易,那您绝对正确。
  • 过滤将是 o(N) 我猜 .. 很难用平均排序击败 ;)
  • @Duncan C 谢谢你,先生。也感谢您的澄清。
【解决方案2】:

我认为,这应该是一个很好的起点,但我无法提供工作代码,因为没有明确的定义,所以:

// Result with minimum range
// Assuming that DateRangeObject has start and end properties of NSDate
DateRangeObject *result = nil;
// Array containing DateRangeObject objects
NSArray *arr /* = TODO: provide the content for an array */;
if (arr.count) { /* only if the array contains something */
    // Initial result
    result = arr[0];
    double minTS = DBL_MAX; // max double value, not zero ;) lol
    for (DateRangeObject *dro in arr) {
        // Get the timestamps for start and end;
        double tss = [dro.start timeIntervalSince1970];
        double tse = [dro.end timeIntervalSince1970];
        // Difference between end and start (positive value)
        double diff = tse - tsa;
        if (minTS < diff) {
            minTS = diff;
            // Current minimum
            result = dro;
        }
    }
}

【讨论】:

    猜你喜欢
    • 2015-06-26
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    相关资源
    最近更新 更多