So I'm not exactly sure if the title fits it best, but here's what the array looks like:

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'
          )
)

How I'd like this data to be sorted would be the following:

  1. Preserve the order of the categories
  2. Within the categories, order by date DESC
  3. If dates appear multiple times, order by data alphabetically ASC

The example array would then be sorted to array ([0], [1], [4], [2], [3]), more specifically:

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'
          )
)

My issue is I know I'll need usort and/or array_multisort(), but I'm not sure exactly sure how to efficiently iterate through a loop in order to sort with the criteria I gave.

share|improve this question

Can you show us the desired output of the array above? – Tim Cooper Nov 3 '11 at 15:59
I went ahead and added some clarity. – Charles Smith Nov 3 '11 at 16:25
feedback

1 Answer

up vote 1 down vote accepted

Supposing your array in $data variable, try this:

<?php
$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);

// outputs

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"
  }
}
share|improve this answer
i think you should apply this sort for each amount of date. You create an array containing the variety of dates and the sort by category and then data. After that, merge the arrays by date. – gustavotkg Nov 3 '11 at 16:24
I got your problem now, see my code. – gustavotkg Nov 3 '11 at 17:26
This works, and I accepted the answer; however, by adding a key between 0 and 1 (renumbering them) array ( "category" => 'Value_1', "date" => '01/02/2011', "data" => 'B') it no longer works. I'll try to figure it out. – Charles Smith Nov 3 '11 at 17:39
ops... Just move $prevDate and others inside the loop! Look my code now – gustavotkg Nov 3 '11 at 17:53
Also, you need to add && $index > 0 to the if statements that could be effected from reading out of bounds data. – Charles Smith Nov 3 '11 at 17:58
show 4 more comments
feedback

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.