按天/月iOS将数组排序为子数组

时间:2014-06-17 15:26:14

标签: ios objective-c sorting

所以我有一份工作要做,所有的解决方案都非常复杂,我想知道你们是否可以帮助我。

我有一个数组(_dataArray),其中包含许多字典(条目),每个字典中都有一个NSdate值和一个浮点值。

我需要接受我的main(_dataArray)并按日期对条目进行排序并放置同一天内的每个条目(占时区)并将其放入其自己的数组中,然后放入所有这些子数组(每个数组包含来自同一天的条目)到另一个数组中,按顺序保存所有日期数组(对象:0是今天或最接近今天的日期并向后移动,因此数组中的最后一个对象将是一个日期数组离今天最远)。

我的所有尝试都只涉及在数组之后加载和加载或者对数组进行更新,并且方法变得有点笨拙,希望你们可能有一些有效解决方案的建议。

提前感谢任何建议。

3 个答案:

答案 0 :(得分:1)

首先我使用此代码生成随机日期

@implementation DateHelper

+(NSDate *)randomDate
{
    NSDateComponents *c = [[NSDateComponents alloc] init];
    c.month = arc4random_uniform(12) +1;

    switch (c.month) {
        case 2:
            c.day = arc4random_uniform(28)+1;
            break;
        case 4:
            case 6:
            case 9:
            case 11:
            c.day = arc4random_uniform(30)+1;
            break;
        default:
            c.day = arc4random_uniform(31)+1;
    }

    c.year = arc4random_uniform(5)+ 2010;
    c.hour = arc4random_uniform(24);
    c.minute = arc4random_uniform(4) *15;
    return [[NSCalendar currentCalendar] dateFromComponents:c];        
}

我称之为

NSMutableArray *dates = [@[] mutableCopy];
for(int i = 0; i < 2000; ++i){
    [dates addObject:[DateHelper randomDate]];

}

只是为了让你在同一页上。


聚类日期:

DateHelper中的此方法会将给定的日期列表聚集到指定的单位(年,月,日,......)

+(NSMutableDictionary *)dates:(NSArray *)dates byUnit:(NSCalendarUnit)unit
{
    NSMutableDictionary *datesByUnit = [@{} mutableCopy];
    [dates enumerateObjectsUsingBlock:^(NSDate *date, NSUInteger idx, BOOL *stop) {
        NSDateComponents *c = [[NSCalendar currentCalendar] components:unit fromDate:date];
        NSInteger v = [c valueForComponent:unit];
        if (![[datesByUnit allKeys] containsObject:@(v)]) {
            datesByUnit[@(v)] = [@[] mutableCopy];
        }
        [datesByUnit[@(v)] addObject:date];
    }];


    return datesByUnit;
}

如果我们将其称为年份,则返回的字典将包含n到m的键,表示找到的最低和最高年份数。密钥的对象是一个包含该年内所有日期的可变字典。

如果我们多年来迭代,我们现在可以通过月份和一年中的月份日期。因此,对于每年,现在将有一个字典,其中1到12的键表示月份。现在我们拿这个清单并且做了几天。

NSMutableDictionary *years = [DateHelper dates:dates byUnit:NSYearCalendarUnit];
[[years allKeys] enumerateObjectsUsingBlock:^(NSNumber *year, NSUInteger idx, BOOL *stop) {
    years[year] = [DateHelper dates:years[year] byUnit:NSMonthCalendarUnit];
}];

[[years allKeys] enumerateObjectsUsingBlock:^(NSNumber *year, NSUInteger idx, BOOL *stop) {
   [[years[year] allKeys] enumerateObjectsUsingBlock:^(NSNumber *month, NSUInteger idx, BOOL *stop) {
       years[year][month] = [DateHelper dates:years[year][month] byUnit:NSDayCalendarUnit];
   }];
}];

不,你今天可以将日期分解成组件并使用它们来查询字典。


数组years现在已聚类为

2014 =     {
    11 =         {
        14 =             (
            "2014-11-14 09:00:00 +0000"
        );
    };
    9 =         {
        3 =             (
            "2014-09-03 05:30:00 +0000"
        );

    5 =         {
        28 =             (
            "2014-05-28 10:00:00 +0000"
        );
        6 =             (
            "2014-05-06 02:15:00 +0000"
        );
    };
    3 =         {
        31 =             (
            "2014-03-31 09:15:00 +0000"
        );
        27 =             (
            "2014-03-27 09:15:00 +0000"
        );
        23 =             (
            "2014-03-23 10:00:00 +0000"
        );
    };
    1 =         {
        15 =             (
            "2014-01-15 05:00:00 +0000"
        );
        8 =             (
            "2014-01-08 12:15:00 +0000"
        );
        5 =             (
            "2014-01-05 04:45:00 +0000"
        );
    };
    12 =         {
        18 =             (
            "2014-12-18 02:00:00 +0000"
        );
    };

    8 =         {
        16 =             (
            "2014-08-16 12:45:00 +0000"
        );
    };
    4 =         {
        27 =             (
            "2014-04-27 12:15:00 +0000",
            "2014-04-27 02:45:00 +0000"
        );
        8 =             (
            "2014-04-08 11:15:00 +0000",
            "2014-04-08 12:45:00 +0000"
        );
        23 =             (
            "2014-04-23 09:45:00 +0000"
        );
    };
};
2010 =     {
    11 =         {
        14 =             (
            "2010-11-14 08:15:00 +0000"
        );
        8 =             (
            "2010-11-08 10:00:00 +0000"
        );
    };
    9 =         {
        24 =             (
            "2010-09-24 08:45:00 +0000"
        );
        17 =             (
            "2010-09-17 02:15:00 +0000"
        );
    };
    7 =         {
        30 =             (
            "2010-07-30 09:45:00 +0000"
        );
        12 =             (
            "2010-07-12 11:45:00 +0000"
        );
        8 =             (
            "2010-07-08 10:30:00 +0000"
        );
    };
    5 =         {
        19 =             (
            "2010-05-19 05:45:00 +0000"
        );
        5 =             (
            "2010-05-05 07:45:00 +0000"
        );
    };
    3 =         {
        15 =             (
            "2010-03-15 12:30:00 +0000"
        );
        4 =             (
            "2010-03-04 10:30:00 +0000"
        );
        11 =             (
            "2010-03-11 11:15:00 +0000"
        );
    };
    1 =         {
        30 =             (
            "2010-01-30 08:15:00 +0000"
        );
        19 =             (
            "2010-01-19 02:30:00 +0000"
        );
        28 =             (
            "2010-01-28 11:15:00 +0000"
        );
        11 =             (
            "2010-01-11 05:15:00 +0000",
            "2010-01-11 11:30:00 +0000"
        );
        7 =             (
            "2010-01-07 07:15:00 +0000"
        );
        3 =             (
            "2010-01-03 09:15:00 +0000"
        );
        17 =             (
            "2010-01-17 09:45:00 +0000"
        );
    };
    12 =         {
        28 =             (
            "2010-12-28 03:45:00 +0000"
        );
        3 =             (
            "2010-12-03 13:45:00 +0000"
        );
        14 =             (
            "2010-12-14 07:30:00 +0000",
            "2010-12-14 13:15:00 +0000"
        );
        23 =             (
            "2010-12-23 13:00:00 +0000"
        );
        4 =             (
            "2010-12-04 02:15:00 +0000"
        );
    };
    10 =         {
        24 =             (
            "2010-10-24 01:30:00 +0000"
        );
        6 =             (
            "2010-10-06 09:00:00 +0000"
        );
    };
    8 =         {
        9 =             (
            "2010-08-09 07:45:00 +0000"
        );
        13 =             (
            "2010-08-13 09:45:00 +0000"
        );
    };
    4 =         {
        17 =             (
            "2010-04-17 07:15:00 +0000"
        );
        13 =             (
            "2010-04-13 01:00:00 +0000",
            "2010-04-13 10:30:00 +0000"
        );
        //......

完整的命令行示例程序

#import <Foundation/Foundation.h>




@interface DateHelper : NSObject

+(NSDate *)randomDate;
+(NSMutableDictionary *)dates:(NSArray *)dates byUnit:(NSCalendarUnit)unit;
@end

@implementation DateHelper

+(NSDate *)randomDate
{
    NSDateComponents *c = [[NSDateComponents alloc] init];
    c.month = arc4random_uniform(12) +1;

    switch (c.month) {
        case 2:
            c.day = arc4random_uniform(28)+1;
            break;
        case 4:
            case 6:
            case 9:
            case 11:
            c.day = arc4random_uniform(30)+1;
            break;
        default:
            c.day = arc4random_uniform(31)+1;
    }

    c.year = arc4random_uniform(5)+ 2010;
    c.hour = arc4random_uniform(12)+ 3;
    c.minute = arc4random_uniform(4) *15;
    return [[NSCalendar currentCalendar] dateFromComponents:c];


}


+(NSMutableDictionary *)dates:(NSArray *)dates byUnit:(NSCalendarUnit)unit
{
    NSMutableDictionary *datesByUnit = [@{} mutableCopy];
    [dates enumerateObjectsUsingBlock:^(NSDate *date, NSUInteger idx, BOOL *stop) {
        NSDateComponents *c = [[NSCalendar currentCalendar] components:unit fromDate:date];
        NSInteger v = [c valueForComponent:unit];
        if (![[datesByUnit allKeys] containsObject:@(v)]) {
            datesByUnit[@(v)] = [@[] mutableCopy];
        }
        [datesByUnit[@(v)] addObject:date];
    }];


    return datesByUnit;
}

@end



int main(int argc, const char * argv[])
{


    @autoreleasepool {
        NSMutableArray *dates = [@[] mutableCopy];
        for(int i = 0; i < 200; ++i){
            [dates addObject:[DateHelper randomDate]];

        }
        NSMutableDictionary *years = [DateHelper dates:dates byUnit:NSYearCalendarUnit];
        [[years allKeys] enumerateObjectsUsingBlock:^(NSNumber *year, NSUInteger idx, BOOL *stop) {
            years[year] = [DateHelper dates:years[year] byUnit:NSMonthCalendarUnit];
        }];

        [[years allKeys] enumerateObjectsUsingBlock:^(NSNumber *year, NSUInteger idx, BOOL *stop) {
           [[years[year] allKeys] enumerateObjectsUsingBlock:^(NSNumber *month, NSUInteger idx, BOOL *stop) {
               years[year][month] = [DateHelper dates:years[year][month] byUnit:NSDayCalendarUnit];
           }];
        }];

    }
    return 0;
}

答案 1 :(得分:1)

对于问题的第一部分,将日期转换为月/日桶,最好的办法是使用NSDateComponents:

例如:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [NSDate date];
NSLog(@"%@", [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date]);

在我的电脑上,这会产生:

<NSDateComponents: 0x61000074d940>
     Calendar Year: 2014
     Month: 6
     Leap month: no
     Day: 17

这是我的时区的格里高利日期。您可以使用新的NSCalendar实例并根据需要设置时区。

对于第二部分,您需要中间结构来转换任何最终结构。一般地描述它,我希望你的输出是Array<Pair<NSDateComponents,Array<Pair<NSDate,Float>>>,这意味着你需要这样的类:

@interface DateFloatPair
@property (copy) NSDate *date;
@property (assign) float value;
@end

@interface ComponentArrayPair
@property (copy) NSDateComponents *components;
@property (copy) NSArray *samples;
@end

即使你最后不关心这些信息,坚持下去也会对排序有所帮助。

我会遍历你的初始数组/字典并构建一个我将描述为NSMutableDictionary<NSDateComponents,NSMutableArray<DateFloatPair>>的新字典。每次遇到日期/浮动时,创建一个DateFloatPair和NSDateComponents并尝试插入:

if (newDictionary[components]) {
    [newDictionary[components] addObject:pair];
} else {
    newDictionary[components] = [NSMutableArray arrayWithObject:pair];
}

获得此词典后,您可以将其转换为NSArray<ComponentArrayPair>。循环时,可以在日期键上对DateFloatPair数组进行排序。然后,您可以通过在组件上执行自定义比较器或在内部数组中的第一个日期进行比较来对外部数组进行排序。

答案 2 :(得分:0)

我正在努力解决你的问题,但我认为你想把浮点数的值放在数组中的字典中不同的数据结构中。新的数据结构也是一个数组,但是这个数组包含带有浮点数的数组,其中外部数组具有“从今天开始的天数”,因为它是索引键。

画报

自:

  • NSArray - 没有用于索引的特定键
    • NSDictionary - 使用的特定密钥,我称之为“日期”和“值”
      • 的NSDate

到:

  • NSArray - 过去的天数是索引键
    • NSArray - 没有具体的索引

代码

进入循环前设置。这可能是一个init函数,如initWithData:(NSArray)数据

NSDate *today = [[NSDate alloc] init];
double secondsInDay = 24 * 60 * 60;
self.days = [[NSMutableArray init] alloc];

然后你必须弄清楚源数据中所有这些日期已经存在多久了。

for (NSDictionary *data in __dataArray)
{
    NSDate *itemDate = (NSDate *) [data objectForKey:@"date"];
    // Storing numbers directly in a dictionary is hard
    // You might need a different type of conversion here...
    NSNumber *itemValue = [NSNumber numberWithFloat:[[data objectForKey@"value"] floatValue]];
    // We want the days to start counting from 0 from today, this will be negative value of seconds
    NSTimeInterval *timeBeforeNow = [itemDate timeIntervalSince:today];

    // We only want the full days and they should be positive
    int daysBeforeNow = -floor(timeBeforeNow / secondsInDay);

    // Call to separate method to avoid clutter
    [self addToArray:itemValue forKey:daysBeforeNow];
}

- (void)addToArray:(NSNumber *)value forKey:(int)daysBeforeNow;
{
    if (self.days[daysBeforeNow] == nil)
    {
         self.days[daysBeforeNow] = [[NSMutableArray alloc] init];
    }

    NSMutableArray *today = (NSMutableArray *)self.days[daysBeforeNow];
    [today addObject:value];
}