Сортировать массив PHP по нескольким значениям в подмассивах - PullRequest
2 голосов
/ 03 ноября 2011

Так что я не совсем уверен, подходит ли заголовок лучше всего, но вот как выглядит массив:

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(), но я 'я точно не уверен, как эффективно выполнять итерации цикла, чтобы выполнить сортировку по критериям, которые я дал.

Ответы [ 2 ]

3 голосов
/ 13 октября 2012

Ваша проблема может быть легко решена с хорошей функцией сравнения и uasort() или usort().Вот как это работает:

Ваша функция сравнения принимает два параметра, которые являются элементами сортируемого массива.Возвратите -1, если первый параметр должен появиться первым в отсортированном массиве, верните 1, если второй параметр должен появиться первым, и верните 0, если оба считаются равными в порядке сортировки.

Ваш критерий заказа выглядит так:Сортировать по категории.Если категория одинакова, сортируйте по дате.Если дата совпадает, сортируйте по данным.

К сожалению, ваш массив неправильно структурирован.Что если другая категория = Value_3 появится как последний элемент в массиве.Должно ли оно быть сгруппировано с другими записями Value_3, или оно должно быть отсортировано отдельно?В зависимости от этого ответа, массив должен быть реструктурирован для упрощения сортировки.

Еще одним улучшением является способ хранения даты.Американский формат даты полностью непригоден для сортировки, ни в виде строки, ни в виде числового значения.Либо преобразуйте его в метку времени Unix, либо используйте формат даты ISO «ГГГГ-ММ-ДД».И то, и другое можно легко сравнить без лишних слов.

1 голос
/ 03 ноября 2011

Предположим, ваш массив в переменной $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"
    }
}
...