【问题标题】:Cluster Timestamps by Date按日期划分的集群时间戳
【发布时间】:2014-04-20 10:34:02
【问题描述】:

我有一个包含时间戳的数组。我想知道 Facebook 等应用程序如何集群帖子。为清楚起见,假设您有一组时间戳,并希望按以下方式对时间戳进行分组:

  • 今天
  • 本周
  • 本月
  • 一月、二月、三月
  • 2013
  • 2012年等

重要的是,“本月”中的帖子不要在“本周”中重复,而这些帖子也不要在“今天”中重复。另外,我在上面对一月、二月和三月进行了硬编码。该脚本应在技术上检测一年中的前几个月。我无法完全编写一个算法来完全实现这一点。这就是我所拥有的。

<?php
    $posts = array(
        array('post_id' => 7, 'timestamp' => '2014-04-20 20:17:49'),
        array('post_id' => 6, 'timestamp' => '2014-04-07 20:17:49'),
        array('post_id' => 5, 'timestamp' => '2014-03-17 20:17:49'),
        array('post_id' => 4, 'timestamp' => '2014-02-14 20:17:49'),
        array('post_id' => 3, 'timestamp' => '2014-01-09 20:17:49'),
        array('post_id' => 2, 'timestamp' => '2013-09-23 20:17:49'),
        array('post_id' => 1, 'timestamp' => '2012-09-23 20:17:49')
    );

    $today = strtotime(date("Y-m-d"));
    $week_start = strtotime('last sunday', strtotime('tomorrow'));
    $month_start = strtotime(date_create(date("Y-m-d"))->modify('first day of this month')->format("Y-m-d"));
    $year_start = strtotime(date_create(date("Y-m-d"))->modify('first day of january 2014')->format("Y-m-d"));

    foreach ($posts as $post)
    {
        $item = strtotime($post['timestamp']);

        if ($item >= $today)
        {
            // Today
            echo '<br><br>' . 'Today' . '<br>';
            echo $post['post_id'] . '<br>';
        }
        else if (($item <= $today) && ($item >= $week_start))
        {
            // This week
            echo '<br><br>' . 'This week' . '<br>';
            echo $post['post_id'] . '<br>';
        }
        else if (($item <= $week_start) && ($item >= $month_start))
        {
            // This month
            echo '<br><br>' . 'This month' . '<br>';
            echo $post['post_id'] . '<br>';
        }
        else if (($item <= $month_start) && ($item >= $year_start))
        {
           // This year
           echo '<br><br>' . 'This year' . '<br>';
           echo $post['post_id'] . '<br>';
        }
    }

此脚本在“本月”之前有效,其余的仅按“今年”进行聚类。我无法按月对它们进行分类,也无法在今年之前进行分类。实现这种级别的聚类并快速完成的最佳方法是什么?

【问题讨论】:

    标签: php algorithm


    【解决方案1】:

    这有点粗糙,但应该可以完成这项工作。

    您在当年 1 月之后提到分组应该回到当年(2013 年、2012 年等) - 好吧,为了有点味道,我还添加了“去年”的额外限制,只是这样你可以看到datetime formats 的可能性。

    我还添加了一个附加帖子,以便您可以看到“本周”正常工作。虽然我没有彻底测试边界,所以可能还有一点改进的空间。

    $posts = array(
        array('post_id' => 8, 'timestamp' => '2014-04-20 20:17:49'),
        array('post_id' => 7, 'timestamp' => '2014-04-16 20:17:49'),
        array('post_id' => 6, 'timestamp' => '2014-04-07 20:17:49'),
        array('post_id' => 5, 'timestamp' => '2014-03-17 20:17:49'),
        array('post_id' => 4, 'timestamp' => '2014-02-14 20:17:49'),
        array('post_id' => 3, 'timestamp' => '2014-01-09 20:17:49'),
        array('post_id' => 2, 'timestamp' => '2013-09-23 20:17:49'),
        array('post_id' => 1, 'timestamp' => '2012-09-23 20:17:49')
    );
    
    // Set some limits
    $limits = array(
        array('name' => 'Today',      'date' => new DateTime('today')),
        array('name' => 'This Week',  'date' => new DateTime('last sunday')),
        array('name' => 'This Month', 'date' => new DateTime('first day of this month midnight')),
        array('name' => 'Last Year',  'date' => new DateTime('first day of last year midnight')),
    );
    
    // Backfill months from this month to January of this year
    for ($m = date('m') - 1; $m > 0; $m--) {
        $dateTime = new DateTime(sprintf('first day of %d month ago midnight', $m));
        $limits[] = array('name' => $dateTime->format('F'), 'date' => $dateTime);
    }
    
    // Sort the limits
    uasort($limits, function ($date1, $date2) {
        if ($date1['date'] === $date2['date']) {
            return 0;
        }
        return $date1['date'] > $date2['date'] ? -1 : 1;
    });
    
    // Find out where each post falls
    foreach ($posts as $post) {
    
        $timestamp = new DateTime($post['timestamp']);
    
        // Default to the fallback (the year)
        $formatted = $timestamp->format('Y');
    
        foreach ($limits as $limit) {
            if ($timestamp >= $limit['date']) {
                $formatted = $limit['name'];
                break;
            }
        }
    
        echo sprintf("ID %s: %s (%s)\n", $post['post_id'], $timestamp->format('dS M Y H:i:s'), $formatted);
    }
    

    【讨论】:

    • 效果很好!我正在学习你是如何做到的。如何防止时期的名称也重复?例如,如果本周有两个帖子,则只显示一次而不是两次。我尝试使用 BOOLEAN 开关,但它只会更加复杂,并且无法按我想要的方式显示。
    • 而不是echoforeach循环结束时取出数据,您可以将它们附加到一个数据结构中,该结构由它落入的时间段键入(即对它们进行分组)。然后,当您想要显示分组数据时,您可以迭代那个额外的“分组”数据结构。您使用bool 的方法(我假设您是否输出了句点标签)也是合理的,但我认为这将取决于您的数据集($posts)也被排序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-01
    • 2022-10-06
    • 2014-10-20
    • 1970-01-01
    • 2014-05-02
    相关资源
    最近更新 更多