0

Possible Duplicate:
Sort multidimensional array by multiple keys

I am trying to find some way how to sort array by key name, but nothing worked so far. The tricky part for me is to sort array by grouping 3 keys. I have this array.

[0] => Array
    (
        [id] => 8
        [zbo_data] => blah
    )

[1] => Array
    (
        [id] => 6
        [szn_data] => blah
    )

[2] => Array
    (
        [id] => 5
        [gcz_data] => blah
    )

[3] => Array
    (
        [id] => 3
        [gcz_data] => blah
    )

[4] => Array
    (
        [id] => 2
        [zbo_data] => blah
    )

[5] => Array
    (
        [id] => 1
        [szn_data] => blah
    )

And I need to sort it by group of 3 in this order: szn_data, zbo_data, gcz_data but I also need to keep the order of [id] (basically primary order by szn_data, zbo_data, gcz_data, secondary [id]). Is there a solution? Or should I construct array differently to be able to sort it? I am trying to figure this out for over 6 hours. Any help is much appreciated.

My desired output is:

[0] => Array
    (
        [id] => 6
        [szn_data] => blah
    )

[1] => Array
    (
        [id] => 8
        [zbo_data] => blah
    )

[2] => Array
    (
        [id] => 5
        [gcz_data] => blah
    )

[3] => Array
    (
        [id] => 1
        [szn_data] => blah
    )

[4] => Array
    (
        [id] => 2
        [zbo_data] => blah
    )

[5] => Array
    (
        [id] => 3
        [gcz_data] => blah
    )
Community
  • 1
  • 1
j.szolony
  • 3
  • 1
  • 5

2 Answers2

1

Use usort and implement your comparison function as you wish. For example:

$result = usort($arr, function($a,$b) {

  $keys = array('szn_data', 'zbo_data', 'gcz_data');
  foreach ($keys as $key) {
    // make sure to add here handling of missing keys
    $diff = strcmp($b[$key], $a[$key]);
    if ($diff!=0) {
      return $diff;
    }
  }

  return $b['id'] - $a['id'];
});
dorsh
  • 23,750
  • 2
  • 27
  • 29
0

Or like this, for any order from max to the min listed in one array

  $arr = array (
    array(
        'id' => 8,
        'zbo_data' => 'blah'
    ),
    array(
        'id' => 6,
        'szn_data' => 'blah'
    ),
    array(
        'id' => 5,
        'gcz_data' => 'blah'
    ),
    array(
        'id' => 3,
        'gcz_data' => 'blah'
    ),
    array(
        'id' => 2,
        'zbo_data' => 'blah'
    ),
    array(
        'id' => 1,
        'szn_data' => 'blah'
    )
  );
  usort($arr, "my_func");
  var_dump($arr);

  function my_func($a, $b)
  {
     $vars = array('szn_data', 'zbo_data', 'gcz_data'); // order of the keys
     $id1 = $a['id']; $id2 = $b['id']; unset($a['id'], $b['id']);
     $index1 = array_search(key($a), $vars);
     $index2 = array_search(key($b), $vars);
     if ($index1 == $index2) {
        if ($id1 == $id2) return 0;
        return ($id1 < $id2) ? 1 : -1;
    }
    return ($index1 < $index2) ? -1 : 1;
  }

ps:

basically primary order by szn_data, zbo_data, gcz_data, secondary [id]

It does not correspond to your desired output. Secondary means comparison of id when other keys are the same.

ps: Updated - this code is NOT nice or perfect, but it will give you what you need

  $vars = array('szn_data', 'zbo_data', 'gcz_data');
  $arr = array (
    array(
        'id' => 8,
        'zbo_data' => 'blah'
    ),
    array(
        'id' => 6,
        'szn_data' => 'blah'
    ),
    array(
        'id' => 5,
        'gcz_data' => 'blah'
    ),
    array(
        'id' => 3,
        'gcz_data' => 'blah'
    ),
    array(
        'id' => 2,
        'zbo_data' => 'blah'
    ),
    array(
        'id' => 1,
        'szn_data' => 'blah'
    )
  );

  $temp = array();
  $cnt = count($arr);
  foreach($arr as $item)
  {
     foreach($vars as $v)
     {
         if (isset($item[$v])) { $temp[$v][$item['id']] = $item; break; }
     }  
  }
  // sort by id
  foreach($vars as $v)
  {
     krsort($temp[$v]);
     $temp[$v] = array_values($temp[$v]);
  }  

  $arr = array(); $i = 0; $j = 0;
  $completed = false;
  do {
     foreach($vars as $v)
     {  
       if ($i++>=$cnt) { $completed = true; break; }           
       if (isset($temp[$v][$j])) $arr[] = $temp[$v][$j];
     }
     $j++; 
  } while (!$completed);
  // output
  var_dump($arr)
Cheery
  • 16,063
  • 42
  • 57
  • This this is sorting array like: szn_data,szn_data,zbo_data,zbo_data,gcz_data,gcz_data but it by group of those 3 (szn_data,zbo_data,gcz_szn_data,szn_data,zbo_data,gcz_data,...) – j.szolony Jan 26 '12 at 21:57
  • @user1172238 read update - you told to do so. primary order is always first and only if items from primary condition are equal, then should be used secondary one. ps: ok, I got it. let me see. – Cheery Jan 26 '12 at 22:00
  • @Cherry yeah, sorry about the ordering. Its not like I wrote first time. – j.szolony Jan 26 '12 at 22:22
  • @Cherry Working like a charm. Thank you very much for help! I much appreciate it! – j.szolony Jan 26 '12 at 22:42
  • @user1172238 there might be some glitches in the part where I tried to take into account different number of the original elements (not multiple of 3). check it if you can. – Cheery Jan 26 '12 at 22:48