【问题标题】:Clustering data with dates by hour, day, week, month, year objective c按小时、天、周、月、年目标 c 聚类数据
【发布时间】:2014-01-16 04:40:00
【问题描述】:

我有一个具有时间和计数属性的 Stat 对象。我有一个(按时间排序)每小时来的这些对象的列表。我想集群显示。 在目标 c 中是否有一种按时间对数据进行聚类的好方法?还是比下面的幼稚算法更好的算法?

这是一个每周做一次的例子。其他类似,但您更改了日期组件。

-(void) makeWeeklyData{

    Stat *prev = self.hourlyData[0];
    NSInteger sum = 0;
    NSMutableArray *weeklyData = [NSMutableArray array];
    for (CSInstallStat *data in self.hourlyData) {
        NSDateComponents *itemComps = [[NSCalendar currentCalendar] components:kCFCalendarUnitWeekOfYear | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:data.time];
        [itemComps setCalendar:[NSCalendar currentCalendar]];

        NSDateComponents *currComps = [[NSCalendar currentCalendar] components:kCFCalendarUnitWeekOfYear | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:prev.time];
        [currComps setCalendar:[NSCalendar currentCalendar]];

        if ([itemComps weekOfYear] == [currComps weekOfYear] && [itemComps month] == [currComps month] && [itemComps year] == [currComps year])  {//Same Week
            sum += data.count;
        } else if([itemComps weekOfYear] >= [currComps weekOfYear] && [itemComps month] == [currComps month] && [itemComps year] == [currComps year]) { //Next Week

            Stat *stat = [[CSInstallStat alloc] init];
            stat.time = [currComps date];
            stat.count = sum;
            stat.timeAccuracy  = ENUMWeekly;
            [weeklyData addObject:stat];
            sum = 0;
            sum += data.count;
            prev = data;
        } else {
            prev = data;
        }

    }
    self.weeklyData = weeklyData;


}

【问题讨论】:

  • 我的MBCalendarKit 库包含一些您可能会觉得有用的 NSCalendar 和 NSDate 类别。

标签: objective-c nsdate nsdatecomponents


【解决方案1】:

如果我正在实施这种系统,我会倾向于在对象进入时维护统计数据。因此,假设我们有一个“每周数据”数组,并且为了争论起见,假设我们想要保留 52 周的价值。在你的类中,声明成员变量:

NSCalendar *gregorianCalendar;
unsigned    lastItemWeek;
struct weekinfo {
  unsigned frequency;
  unsigned month;
  int year;
} weeklyStats[53];

当一个新的值进来时,你就去做

- (id)init
{
  if ((self = [super init])) {
    ...
    /* Must fix the calendar we're using, or at least understand the one we're
       using.  Using [NSCalendar currentCalendar] is potentially risky as we
       don't necessarily know what that is. */
    gregorianCalendar = [[NSCalendar alloc]
                         initWithCalendarIdentifier:NSGregorianCalendar];
    ...
  }
}

- (void)gotNewItemWithDate:(NSDate *)date
{
  NSDateComponents *itemComps = [gregorianCalendar
                                 components:(NSWeekOfYearCalendarUnit
                                             | NSCalendarUnitMonth | NSCalendarUnitYear)
                                 fromDate:date];
  unsigned week = [itemComps week] - 1; // This runs from 0 to 52 inclusive
  unsigned month = [itemComps month];
  int year = [itemComps year];

  if (week == lastItemWeek)
    ++weeklyStats[week].frequency;
  else {
    // Some years don't have week 53 (which we store in weeklyStats[52])
    if (week == 0 && lastItemWeek == 51)
      weeklyStats[52] = (struct weekinfo){ 0, 0, 0 };

    weeklyStats[week] = (struct weekinfo){ 1, month, year };
  }
  lastItemWeek = week;
}

如果你真的想要,你可以将它存储在 Stat 对象中,但这似乎有点不必要。

很明显,您可以扩展此方法以维护每日统计数据等。

两个警告:

  1. 几周很棘手;有些年份有 53 周,有些年份有 52 周。因此,weeklyStats[52] 可能有效,也可能无效。如果我们最后一次是在第 52 周,我选择在第 0 周时清除它。

  2. weeklyStats[lastItemWeek] 给出的元素不是最终值。

【讨论】:

  • 您在以周为单位硬编码年份长度 - 这对于某些日历系统来说会中断。
  • @Moshe 是的。这就是为什么代码也对日历进行硬编码,这就是为什么在上面的代码中有一个很大的注释。当然,只有当 OP 期望使用用户的本地化日历而不是公历(IMO 令人怀疑)时,这才是一个问题。
  • 你会对这种事情感到非常惊讶。 Apple 鼓励本地化。
  • @Moshe 我很清楚我们鼓励本地化,非常感谢(我从 2000 年开始为 Apple 系统编写代码)。但是,如果我对 OP 的意图是正确的,他只想获得每周的统计数据。实际上,一年中有多少周这样做并不重要。重要的是输出端有连续的数据流。显式使用公历来获取周数是实现这一目标的便捷方式。
猜你喜欢
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多