【问题标题】:Cumulative sum of unique elements sorted by other element in a nested array嵌套数组中按其他元素排序的唯一元素的累积和
【发布时间】:2016-04-21 20:58:22
【问题描述】:

我有以下 MySQL 查询(timestamp 显然是 Unix 时间):

SELECT usr_id, CONCAT(YEAR(FROM_UNIXTIME(timestamp)), "/", MONTH(FROM_UNIXTIME(timestamp)), "/", DAY(FROM_UNIXTIME(timestamp))) as date_stamp
FROM table
ORDER BY YEAR(FROM_UNIXTIME(timestamp)), MONTH(FROM_UNIXTIME(timestamp)), DAY(FROM_UNIXTIME(timestamp));

这会产生这样的结果:

$arr = array(
    array('usr_id'=>3, 'date_stamp'=>'2011/6/6'),
    array('usr_id'=>2, 'date_stamp'=>'2011/6/20'),
    array('usr_id'=>2, 'date_stamp'=>'2011/6/20'), // same id and date as above
    array('usr_id'=>5, 'date_stamp'=>'2011/6/20'), // same date as above
    array('usr_id'=>1, 'date_stamp'=>'2011/6/21'),
    array('usr_id'=>4, 'date_stamp'=>'2011/6/21'), // same date as above
    array('usr_id'=>2, 'date_stamp'=>'2011/6/21'), // same date as above...
        //... and same id as a day before
);

我想把它变成这样的:

$arr = array(
    array('sum'=>1, 'date_stamp'=>'2011/6/6'),
    array('sum'=>3, 'date_stamp'=>'2011/6/20'), // +2 as one of the 3...
        //... for this date was a duplicate
    array('sum'=>5, 'date_stamp'=>'2011/6/21'), // +2 as one of the 3...
        //... was already there on a different day
);

这是我尝试过的,但后来我才意识到它只关注给定日期的唯一性,而不是我打算做的整个数组:

$sum = 0;
$tempRes = array();
$result = array(); 
$date = null;
foreach($arr as $row)
{
    $date = $row['date_stamp'];
    if (!in_array($row['usr_id'], $tempRes))
        $tempRes[$date][] = $row2['usr_id'];
}
foreach ($tempRes as $date2 => $ids)
{
    $sum += count($ids);
    $result[] = array($date2, $sum);
}

基本上,目的是产生每天usr_id 数量的累积总和,并确保相同的usr_id 在整个数组中仅计为一个,即。按天排序的唯一usr_id' 的累积总和。

如果您有更好地优化 MySQL 查询的想法,也欢迎。

编辑:我希望“累积”发生在整个数组上,而不仅仅是每天,就像我的示例输出中那样,即。第 1 天是 1,第 2 天是 3 (1+2),第 3 天是 5 (3+2)...等等。

【问题讨论】:

  • 您是否总是希望 ID 在最早日期(或特定日期)计算,并且您是否试图避免两次传递数据?
  • @DaveCoast 重要的是它按日期升序排序,我希望省略已在任何日期使用的 id。
  • 看到一个优雅的解决方案会很有趣。我必须分两步完成,查询分组 ID 和最小日期,然后用 PHP 中的运行总数计算 ID。
  • @DaveCoast 日期已经排序,我想挑战是,至少对我来说,不仅要在特定日期内有效地取出 id 的重复项,而且要在整个结果堆栈中取出......
  • 是的,但是使用MIN(date) 您只能在最早的日期获得一次 ID,这不是我们想要的吗?

标签: php mysql arrays unique


【解决方案1】:

您可以首先按天对唯一用户进行分组,如下所示:

foreach ($arr as $item) {
    $days[$item['date_stamp']][$item['usr_id']] = 1; // value is irrelevant
}

然后您可以创建一个包含所有用户的数组,将每天的用户合并到其中并计算其结果以获得累积总和。

$all_users = array();
foreach ($days as $day => $users) {
    $all_users = $all_users + $users;
    $result[] = array('sum' => count($all_users), 'date_stamp' => $day);
}

【讨论】:

  • 我同时编辑了这个问题,并在原始数组中添加了一个额外的行以更好地展示我想要的内容:额外的行与 2011/6/20 的重复行具有相同的 id (2) ,您的脚本将只处理一个重复,即2011/6/20 中的一个,但会忽略新日期中的那个,因此它也会将其添加到计数中而不是忽略它...更新了您的评估:3v4l.org/pKcJj - 最终结果应该是 5,而不是 6...希望这是有道理的... :(
  • 哦,是的,我忘了 array_merge 如何处理数字键。我改为数组联合(+),它现在似乎工作正常。 3v4l.org/TvOGJ
  • 谢谢!这是一个有趣的问题。
  • 很高兴你喜欢它! ;)
【解决方案2】:

我会在 SQL 中这样做。

类似的东西 - 这是伪代码,当然不是真正的 SQL,因为我是 MSSQL 开发人员,但想法是有道理的。

这将首先选择所有唯一用户 ID 及其日期。然后它将按日期对它们进行分组。在此之后,只需在 PHP 中运行它并添加。

SELECT 
    COUNT(usr_id)
    date_stamp
    ts
FROM
    (
        SELECT 
            DISTINCT usr_id,
            timestamp as ts,
            CONCAT(YEAR(FROM_UNIXTIME(timestamp)), "/", MONTH(FROM_UNIXTIME(timestamp)), "/", DAY(FROM_UNIXTIME(timestamp))) as date_stamp
        FROM 
            table
    )
GROUP BY 
    date_stamp
ORDER BY 
    ts

【讨论】:

  • 这只是提供给定日期内的计数,不做累积,但我想我可以用 PHP 做,所以这实际上是一个很好的建议,谢谢。跨度>
  • 每天唯一 ID 的 COUNT 不是您所追求的吗?应该这样做。
  • 是的,但我也希望它在整个数组中累积,抱歉,如果问题不清楚,让我编辑它...
  • 不确定您所说的累积是什么意思...您将从该查询中得到的信息类似于:array (size=3) '2011/6/6' => 1 '2011/6/20' => 3 '2011/6/21' => 2
  • 是的,我测试了它,它看起来非常接近我想要实现的目标。累积我的意思是2011/6/6应该有1,但2011/6/20应该有3(不是因为有3个id,而是因为1,前一个值+2,第二天的值总共是3),那么对于2011/6/21,遵循相同的逻辑,它将是 5,如 3+2 ......我不确定你的解决方案的一件事是它是否会在一天内只显示不同的 id 或者会在整个数组中唯一(即根本不应该重复 id)...
猜你喜欢
  • 1970-01-01
  • 2015-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
相关资源
最近更新 更多