views:

675

answers:

4
+1  Q: 

PHP: Sort an array

I've got an array with data from a MySQL table in nested set model I'd like to get sorted, not only alphabetical but also with the child nodes directly after the parent node. Example - array to be sorted (before the sorting):

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Kompetenser
            [parent] => 0
            [depth] => 0
        )

    [1] => Array
        (
            [id] => 2
            [name] => Administration
            [parent] => 1
            [depth] => 1
        )

    [2] => Array
        (
            [id] => 11
            [name] => Organisation
            [parent] => 2
            [depth] => 2
        )

    [3] => Array
        (
            [id] => 4
            [name] => Arbetsledning
            [parent] => 2
            [depth] => 2
        )

    [4] => Array
        (
            [id] => 17
            [name] => Planering
            [parent] => 2
            [depth] => 2
        )

    [5] => Array
        (
            [id] => 9
            [name] => Hantverke
            [parent] => 1
            [depth] => 1
        )

    [6] => Array
        (
            [id] => 10
            [name] => Snickeri
            [parent] => 9
            [depth] => 2
        )

    [7] => Array
        (
            [id] => 12
            [name] => Språk
            [parent] => 1
            [depth] => 1
        )

    [8] => Array
        (
            [id] => 13
            [name] => Tolk
            [parent] => 12
            [depth] => 2
        )

    [9] => Array
        (
            [id] => 15
            [name] => Arabiska
            [parent] => 13
            [depth] => 3
        )

    [10] => Array
        (
            [id] => 14
            [name] => Persiska
            [parent] => 13
            [depth] => 3
        )

    [11] => Array
        (
            [id] => 16
            [name] => Polska
            [parent] => 13
            [depth] => 3
        )

    [12] => Array
        (
            [id] => 18
            [name] => Apotekare
            [parent] => 1
            [depth] => 1
        )

    [13] => Array
        (
            [id] => 19
            [name] => Dotkorand
            [parent] => 1
            [depth] => 1
        )

    [14] => Array
        (
            [id] => 21
            [name] => Atomfysik
            [parent] => 19
            [depth] => 2
        )

    [15] => Array
        (
            [id] => 20
            [name] => Fysik
            [parent] => 19
            [depth] => 2
        )

    [16] => Array
        (
            [id] => 22
            [name] => Ekonom
            [parent] => 1
            [depth] => 1
        )

    [17] => Array
        (
            [id] => 23
            [name] => Industriell ekonomi
            [parent] => 22
            [depth] => 2
        )

    [18] => Array
        (
            [id] => 24
            [name] => Filosofi
            [parent] => 1
            [depth] => 1
        )

)

I want the array this way (after the sorting):

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Kompetenser
            [parent] => 0
            [depth] => 0
        )

    [1] => Array
        (
            [id] => 2
            [name] => Administration
            [parent] => 1
            [depth] => 1
        )

    [3] => Array
        (
            [id] => 4
            [name] => Arbetsledning
            [parent] => 2
            [depth] => 2
        )

    [2] => Array
        (
            [id] => 11
            [name] => Organisation
            [parent] => 2
            [depth] => 2
        )

    [4] => Array
        (
            [id] => 17
            [name] => Planering
            [parent] => 2
            [depth] => 2
        )

    [12] => Array
        (
            [id] => 18
            [name] => Apotekare
            [parent] => 1
            [depth] => 1
        )

    [13] => Array
        (
            [id] => 19
            [name] => Dotkorand
            [parent] => 1
            [depth] => 1
        )

    [14] => Array
        (
            [id] => 21
            [name] => Atomfysik
            [parent] => 19
            [depth] => 2
        )

    [15] => Array
        (
            [id] => 20
            [name] => Fysik
            [parent] => 19
            [depth] => 2
        )

    [16] => Array
        (
            [id] => 22
            [name] => Ekonom
            [parent] => 1
            [depth] => 1
        )

    [17] => Array
        (
            [id] => 23
            [name] => Industriell ekonomi
            [parent] => 22
            [depth] => 2
        )

    [18] => Array
        (
            [id] => 24
            [name] => Filosofi
            [parent] => 1
            [depth] => 1
        )

    [5] => Array
        (
            [id] => 9
            [name] => Hantverke
            [parent] => 1
            [depth] => 1
        )

    [6] => Array
        (
            [id] => 10
            [name] => Snickeri
            [parent] => 9
            [depth] => 2
        )

    [7] => Array
        (
            [id] => 12
            [name] => Språk
            [parent] => 1
            [depth] => 1
        )

    [8] => Array
        (
            [id] => 13
            [name] => Tolk
            [parent] => 12
            [depth] => 2
        )

    [9] => Array
        (
            [id] => 15
            [name] => Arabiska
            [parent] => 13
            [depth] => 3
        )


    [10] => Array
        (
            [id] => 14
            [name] => Persiska
            [parent] => 13
            [depth] => 3
        )

    [11] => Array
        (
            [id] => 16
            [name] => Polska
            [parent] => 13
            [depth] => 3
        )

)

As you might see, I want all posts with parent 2 directly after the post with id 2, and so on.

Any help would be highly appreciated. Thank you in advance.

+4  A: 

Don't do this in PHP!

The MySQL server is specificly designed to query AND sort data, read up on the MySQL "ORDER BY" syntax. Doing this on the MySQL server will save run-time, CPU Load and Memory Consumption.

Unkwntech
I just have to mention that I've worked with websites in 5 years and I know very well about the order-by statement in MySQL. Please notice that these data are from a MySQL table in nested set model. Read my comment above.
Ivarska
+1  A: 

Use php's uasort() function to define your own comparison function.

But using MySQL's sorting capabilities would be more appropriate, if it's possible in your case.

macbirdie
Unfortunately, as I've mentioned in the posts above, it's not possible to order these data in a nested set model (as far as I and thousands of other programmers know).Yeah, I did try with uasort() but could just sort them alphabetical and not by parents. Although, I think this function is the right way and would appreciate if someone could help me with a more advanced version of this function (or got any other solution).
Ivarska
A: 

You want to sort it like it is in the DB, multilayered. I don't think uasort can help with this problem because you want to attach the children to the parent.

foreach ($arr as &$val) {
    $arr2[$val['id']] = &$val;
}

ksort($arr2);

foreach ($arr2 as $id => &$val) {
    $parent = $val['parent'];
    if ($parent == 0) {
     continue;
    }
    $arr2[$parent]['children'][$id] = &$val;
}

function flattenArrayByChildren($arr) {
    foreach ($arr as $id => $val) {
     if (isset($val['children'])) {
      $temp = flattenArrayByChildren($val['children']);
      unset($val['children']);
      $out[$id] = $val;
      $out = $out + $temp;
     } else {
      $out[$id] = $val;
     }
    }
    return $out;
}

$arr2 = array(1 => $arr2[1]);

$out = flattenArrayByChildren($arr2);

var_dump($out);

If you absolutely want to save the key, you can just add that to the $val in the first foreach, and retrieve it in the recursive function flattenArrayByChildren and use as key.

OIS
It's awesome if this works! I gonna test later. The performance might not be so good, but I'll probably serialize and store the data.
Ivarska
I've tested your code now. It seems like it's only sorting the children of "Administration" (the first child in "Kompetenser"). The children in "Kompetenser" (all the categories) arn't getting sorted at all, as well as "Tolk". It's also reversing the order of Dotkorand.
Ivarska
Yeah I sorted it by id not alphabetically. You have to sort it alphabetically before you add them as children to an id, and then you have to use $arr instead of $arr2.
OIS
A: 

Problem solved - I made two simple functions. I hope other people could have use of this as well:

class data_comp
{
    var $fetched_tree = array();

    function tree_fetch($parent = 0)
    {
     $query = 'SELECT node.id, node.name, node.parent, (COUNT(parent.name) - 1) AS depth FROM test_competence AS node, test_competence AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.name';
     $result = mysql_query($query) or die(mysql_error());
     $tree = array();

     while($data = mysql_fetch_assoc($result))
     {
      $tree[$data['parent']][$data['id']] = array('name' => $data['name'], 'depth' => $data['depth']);
     }

     $this->tree_print($tree, $parent);
    }

    function tree_print($tree, $parent)
    {
     foreach($tree[$parent] as $id => $value)
     {
      $this->fetched_tree[] = array('id' => $id, 'name' => $value['name'], 'depth' => $value['depth']);

      if(isset($tree[$id]) && is_array($tree[$id]))
      {
       $this->tree_print($tree, $id);
      }
     }
    }
}

Thank you for your time. Any improvements are more than welcome.

Ivarska