【问题标题】:Sort PHP array by multiple values within subarrays按子数组中的多个值对 PHP 数组进行排序
【发布时间】:2011-11-03 15:49:15
【问题描述】:

所以我不确定标题是否最合适,但数组如下所示:

array (
   [0] => array (
              [category] => 'Value_1'
              [date]     => '01/01/2011'
              [data]     => 'A'
          )
   [1] => array (
              [category] => 'Value_3'
              [date]     => '01/01/2000'
              [data]     => 'B'
          )
   [2] => array (
              [category] => 'Value_2'
              [date]     => '01/01/2011'
              [data]     => 'D'
          )
   [3] => array (
              [category] => 'Value_2'
              [date]     => '01/01/2010'
              [data]     => 'A'
          )
   [4] => array (
              [category] => 'Value_2'
              [date]     => '01/01/2011'
              [data]     => 'C'
          )
)

我希望这些数据的排序方式如下:

  1. 保留类别的顺序
  2. 在类别中,按日期 DESC 排序
  3. 如果日期出现多次,则按数据的字母顺序 ASC 排序

然后示例数组将被排序为array ([0], [1], [4], [2], [3]),更具体地说:

array (
   [0] => array (
              [category] => 'Value_1'
              [date]     => '01/01/2011'
              [data]     => 'A'
          )
   [1] => array (
              [category] => 'Value_3'
              [date]     => '01/01/2000'
              [data]     => 'B'
          )
   [2] => array (
              [category] => 'Value_2'
              [date]     => '01/01/2011'
              [data]     => 'C'
          )
   [3] => array (
              [category] => 'Value_2'
              [date]     => '01/01/2011'
              [data]     => 'D'
          )
   [4] => array (
              [category] => 'Value_2'
              [date]     => '01/01/2010'
              [data]     => 'A'
          )
)

我的问题是我知道我需要usort 和/或array_multisort(),但我不确定如何有效地遍历循环以便按照我给出的标准进行排序。

【问题讨论】:

  • 你能告诉我们上面数组的期望输出吗?
  • 我继续并添加了一些清晰度。

标签: php arrays sorting usort


【解决方案1】:

您的问题可以通过一个很好的比较功能和uasort()usort() 轻松解决。以下是它的工作原理:

您的比较函数接受两个参数,它们是您排序的数组的元素。如果第一个参数应该在排序后的数组中出现,则返回 -1,如果第二个参数应该首先出现,则返回 1,如果两者在排序顺序中相等,则返回 0。

您的订单标准如下:按类别排序。如果类别相同,则按日期排序。如果日期相同,则按数据排序。

很遗憾,您的数组结构不正确。如果另一个 category=Value_3 作为数组中的最后一个元素出现怎么办。它应该与其他 Value_3 条目分组,还是应该单独排序?根据这个答案,应该重组数组以便于排序。

另一个改进是存储日期的方式。美国日期格式完全不能用于排序,既不能作为字符串也不能作为数值。将其转换为 unix 时间戳,或使用 ISO 日期格式“YYYY-MM-DD”。两者都可以轻松进行比较。

【讨论】:

    【解决方案2】:

    假设你的数组在 $data 变量中,试试这个:

    $data = Array(
        0 => array(
            "category" => 'Value_1',
            "date" => '01/01/2011',
            "data" => 'A'
        ),
        1 => array(
            "category" => 'Value_3',
            "date" => '01/01/2000',
            "data" => 'B'
        ),
        2 => array(
            "category" => 'Value_2',
            "date" => '01/01/2011',
            "data" => 'D'
        ),
        3 => array(
            "category" => 'Value_2',
            "date" => '01/01/2010',
            "data" => 'A'
        ),
        4 => array(
            "category" => 'Value_2',
            "date" => '01/01/2011',
            "data" => 'C'
        )
    );
    
    $sorted = false;
    foreach ($data as $index => $row) {
        $data[$index]['date'] = strtotime($data[$index]['date']);
    }
    while (!$sorted) {
        $aux = null;
        $prevCat = null;
        $prevDate = null;
        $prevData = null;
        foreach ($data as $index => $row) {
            if ($prevCat != $row['category']) {
                $prevCat = $row['category'];
                $prevDate = $row['date'];
                $prevData = $row['data'];
                continue;
            } else {
                if ($row['date'] > $prevDate) {
                    $sorted = false;
                    $aux = $data[$index - 1];
                    $data[$index - 1] = $row;
                    $data[$index] = $aux;
                    break;
                }
                if ($row['date'] == $prevDate && $row['data'] < $prevData) {
                    $sorted = false;
                    $aux = $data[$index - 1];
                    $data[$index - 1] = $row;
                    $data[$index] = $aux;
                    break;
                }
                $prevCat = $row['category'];
                $prevDate = $row['date'];
                $prevData = $row['data'];
            }
        }
        $sorted = ($aux == null);
    }
    foreach ($data as $index => $row)
        $data[$index]['date'] = date("m/d/Y", $data[$index]['date']);
    var_dump($data);
    

    // 输出

    array(5) {
        [0] => array(3) {
            ["category"] => string(7) "Value_1"
            ["date"] => string(10) "01/01/2011                                                               
            ["data"] => string(1) "A"
        }
        [1] => array(3) {
            ["category"] => string(7) "Value_3"
            ["date"] => string(10) "01/01/2000"
            ["data"] => string(1) "B"
        }
        [2] => array(3) {
            ["category"] => string(7) "Value_2"
            ["date"] => string(10) "01/01/2011"
            ["data"] => string(1) "C"
        }
        [3] => array(3) {
            ["category"] => string(7) "Value_2"
            ["date"] => string(10) "01/01/2011"
            ["data"] => string(1) "D"
        }
        [4] => array(3) {
            ["category"] => string(7) "Value_2"
            ["date"] => string(10) "01/01/2010"
            ["data"] => string(1) "A"
        }
    }
    

    【讨论】:

    • 我认为您应该对每个日期应用这种排序。您创建一个数组,其中包含各种日期和按类别排序,然后是数据。之后,按日期合并数组。
    • 这行得通,我接受了答案;但是,通过在 0 和 1 之间添加一个键(重新编号)array ( "category" =&gt; 'Value_1', "date" =&gt; '01/02/2011', "data" =&gt; 'B') 它不再起作用。我会努力弄清楚的。
    • ops... 只需将$prevDate 和其他人移入循环!现在看看我的代码
    • 另外,您需要将&amp;&amp; $index &gt; 0 添加到可能因读取越界数据而影响的 if 语句中。
    • @CharlesSmith When $index == 0 then $prevData and others are null, which is different from $row['data'] and so...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 2015-02-19
    • 1970-01-01
    • 2015-10-30
    • 2012-06-15
    相关资源
    最近更新 更多