按两个条件对数组进行排序

6

好的,我遇到了一个问题,希望你能协助解决。基本上,我想要完成的是计算过去十二个月的注册总数,从当前月开始。

首先,由于我无法保证每个月都有返回结果,所以我建立了一个数组并用我的查询结果填充它。我成功地提取了所有需要的数据,但是我在"排序"它们方面遇到了麻烦。

我希望能够按如下方式显示它:

当前是10月,所以月份将列如下:

2014年11月,2014年12月,2015年1月,2015年2月,2015年3月,...,2015年10月。

使用这个数组:

$months = array(
            '1'=>array('TOTAL'=>0, 'YEAR'=>NULL), 
            '2'=>array('TOTAL'=>0, 'YEAR'=>NULL), 
            '3'=>array('TOTAL'=>0, 'YEAR'=>NULL), 
            '4'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '5'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '6'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '7'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '8'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '9'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '10'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '11'=>array('TOTAL'=>0, 'YEAR'=>NULL),  
            '12'=>array('TOTAL'=>0, 'YEAR'=>NULL)
        );

然后使用获取到的结果填充它:

key: 1 (January) total: 17 year: 2015
key: 2 (February) total: 20 year: 2015
key: 3 (March) total: 23 year: 2015
key: 4 (April) total: 29 year: 2015
key: 5 (May) total: 26 year: 2015
key: 6 (June) total: 26 year: 2015
key: 7 (July) total: 26 year: 2015
key: 8 (August) total: 24 year: 2015
key: 9 (September) total: 22 year: 2015
key: 10 (October) total: 24 year: 2015
key: 11 (November) total: 30 year: 2014
key: 12 (December) total: 42 year: 2014

这是查询/循环的代码:

    $query = "SELECT MONTH(DATE_ADDED) as MONTH_NUMBER, MONTHNAME(DATE_ADDED) as MONTH_NAME, COUNT(*) as TOTAL_REGISTRATIONS, YEAR(DATE_ADDED) AS YEAR FROM MEMBERS WHERE DATE_ADDED >= (CURDATE() - INTERVAL (DAY(CURDATE()) - 1) DAY) - INTERVAL 11 MONTH GROUP BY MONTH(DATE_ADDED) ORDER BY DATE_ADDED ASC";
    $result = mysql_query($query) or die(mysql_error());

while($row = mysql_fetch_assoc($result)){

    $months[$row['MONTH_NUMBER']]['NAME'] = $row['MONTH_NAME'];
    $months[$row['MONTH_NUMBER']]['TOTAL'] = $row['TOTAL_REGISTRATIONS'];
    $months[$row['MONTH_NUMBER']]['YEAR'] = $row['YEAR'];
    $months[$row['MONTH_NUMBER']]['MONTH_NUM'] = $row['MONTH_NUMBER'];

}

    foreach($months as $key=>$data){
        echo 'key: '.$key. ' ('.$data['NAME'].')   total:   '.$data['TOTAL'].'      year: '.$data['YEAR'].'<br/>';
    }
    exit;

编辑:到目前为止,我已经能够完成以下操作:

key: 12 (December) total: 42 year: 2014
key: 11 (November) total: 30 year: 2014
key: 10 (October) total: 24 year: 2015
key: 9 (September) total: 22 year: 2015
key: 8 (August) total: 24 year: 2015
key: 7 (July) total: 26 year: 2015
key: 6 (June) total: 26 year: 2015
key: 5 (May) total: 26 year: 2015
key: 4 (April) total: 29 year: 2015
key: 3 (March) total: 23 year: 2015
key: 2 (February) total: 20 year: 2015
key: 1 (January) total: 17 year: 2015

使用以下代码:
function sortArray(array $a, array $b) {

    if($a['YEAR'] <= $b['YEAR'] && $a['MONTH_NUM'] < $b['MONTH_NUM']){
        return 1;
    }elseif($a['YEAR'] <= $b['YEAR'] && $a['MONTH_NUM'] > $b['MONTH_NUM']){
        return -1;
    }elseif($a['YEAR'] >= $b['YEAR'] && $a['MONTH_NUM'] > $b['MONTH_NUM']){
        return -1;
    }elseif($a['YEAR'] >= $b['YEAR'] && $a['MONTH_NUM'] < $b['MONTH_NUM']){
        return 1;
    } else {
        return 0;
    }

}
// Sort
uasort($months, 'sortArray');

编辑:您可以看到它按年份正确排序,但将月份列出的顺序是错误的。

编辑:期望输出

key: 11 (November) total: 00 year: 2014
key: 12 (December) total: 00 year: 2014
key: 1 (January) total: 00 year: 2015
key: 2 (February) total: 00 year: 2015
key: 3 (March) total: 00 year: 2015
key: 4 (April) total: 00 year: 2015
key: 5 (May) total: 00 year: 2015
key: 6 (June) total: 00 year: 2015
key: 7 (July) total: 00 year: 2015
key: 8 (August) total: 00 year: 2015
key: 9 (September) total: 00 year: 2015
key: 10 (October) total: 00 year: 2015

最终,我将通过柱状图展示过去一年每月的总数。

不确定这是否是最佳方法,欢迎提出建议。


2
请勿使用mysql_函数,它们已被弃用,请改用mysqli_函数或PDO对象。 - al'ein
1
我从未使用过它,现在我正在研究它的工作原理。我已经将示例应用于我的数据以查看输出,但我需要进一步理解它,以便编写比较函数。 - Imperialized
1
usort/uasort会在数组内部对其进行排序,并在成功时返回true,失败时返回false。每个元素将按照回调函数的返回值进行排序,这使您可以自由地对排序施加任何规则。回调函数获取两个参数,其中$a是一个数组元素,$b是要与$a进行比较的下一个数组元素。比较方法由您决定。返回负数,元素$a将下降。返回正数,它将上升。如果为零,则保持其位置不变。 - al'ein
我该如何让它按多列排序?我已经按年份排序了,但如果我再按月份排序,它会改变年份的顺序。 - Imperialized
1
好的,我会尝试一下。谢谢你的帮助。 - Imperialized
显示剩余10条评论
2个回答

1
我认为你的答案在由"clement.hk"编写的user contribution note,位于PHP文档uasort()函数页面上。我已经对其进行了改编,似乎可以解决你的问题!
<?php

// array reproduction
$months = array(
        '1'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '2'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '3'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '4'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '5'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '6'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '7'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '8'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '9'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '10'=>array('TOTAL'=>0, 'YEAR'=>2015),
        '11'=>array('TOTAL'=>0, 'YEAR'=>2014),
        '12'=>array('TOTAL'=>0, 'YEAR'=>2014)
);

// "clement.hk"'s alternate version of "uasort", where it keeps
// the index order when $a == $b. Credits to him!
function stable_uasort(&$array, $cmp_function) {
    if(count($array) < 2) {
        return;
    }
    $halfway = count($array) / 2;
    $array1 = array_slice($array, 0, $halfway, TRUE);
    $array2 = array_slice($array, $halfway, NULL, TRUE);

    stable_uasort($array1, $cmp_function);
    stable_uasort($array2, $cmp_function);
    if(call_user_func($cmp_function, end($array1), reset($array2)) < 1) {
        $array = $array1 + $array2;
        return;
    }
    $array = array();
    reset($array1);
    reset($array2);
    while(current($array1) && current($array2)) {
        if(call_user_func($cmp_function, current($array1), current($array2)) < 1) {
            $array[key($array1)] = current($array1);
            next($array1);
        } else {
            $array[key($array2)] = current($array2);
            next($array2);
        }
    }
    while(current($array1)) {
        $array[key($array1)] = current($array1);
        next($array1);
    }
    while(current($array2)) {
        $array[key($array2)] = current($array2);
        next($array2);
    }
    return;
}

// the equal comparison is pointless since you have twelve months of the same
// year... we need comparison only when it differs
stable_uasort($months, function ($a, $b) {
/*     if($a['YEAR'] == $b['YEAR']) {
        return 0;
    } */
    return ($a['YEAR'] > $b['YEAR']) ? 1 : -1;
});


echo '<pre>';
print_r($months);

输出:

Array
(
    [11] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2014
        )

    [12] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2014
        )

    [1] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [2] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [3] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [4] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [5] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [6] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [7] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [8] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [9] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

    [10] => Array
        (
            [TOTAL] => 0
            [YEAR] => 2015
        )

)

似乎当进行多级排序时,uasort可能会变得不稳定,而当它们具有相同的值时,它会维护数组索引顺序。 talking是目前在PHP7上针对小型数组(<16)进行修复的,因此,如果你敢尝试,可能值得一试!

谢谢,我会尝试并回帖的! - Imperialized
1
运行得非常好。感谢您的帮助!也感谢来自php.net的那个人! - Imperialized

0

你可以使用usort函数,并在其中添加带有条件的逻辑。按照总值排序的示例代码如下。

function sortFunction($item1, $item2)
{
    return $item1->TOTAL - $item2->TOTAL;
}

usort($months, "sortFunction");

usort / uasort 肯定是解决方案。然而,我正在努力想出实现结果的逻辑。我可以按年份和月份进行排序,但月份会走错路线。它变成了 Dec14、Nov14、Oct15、Sept15 等等。 - Imperialized

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接