PHP - Sort multi-dimensional array by another array

前端 未结 5 1041
忘掉有多难
忘掉有多难 2020-12-06 17:59

I\'m trying to sort a multi-dimensional array by another array, but have so far come up short.
array_multisort seems be working only for real sorting.

Suppose I

相关标签:
5条回答
  • 2020-12-06 18:27

    This would be how I would do. I would use a custom usort function (arr_sort) in conjunction with the $data array.

    <?php
    $order = array(2,3,1);
    $data = array(
        array('id' => 1, 'title' => 'whatever'),
        array('id' => 2, 'title' => 'whatever'),
        array('id' => 3, 'title' => 'whatever')
    );
    function arr_sort($a,$b){
      global $order;
      foreach ($order as $key => $value) {
        if ($value==$a['id']) {
          return 0;
          break;
        }
        if ($value==$b['id']) {
          return 1;
          break;
        }
      }
    }
    usort($data,'arr_sort');
    echo "<pre>";
    print_r($data);
    echo "<pre>";
    
    0 讨论(0)
  • 2020-12-06 18:39

    In your example the ids in the $data array are are numbered consecutively and starting at 1. The code I give below assumes this is always the case. If this is not the case, the code does not work.

    $result = array();
    $index = 0;
    foreach ($order as $position) {
        $result[$index] = $data[$position - 1];
        $index++;
    }
    

    At http://codepad.org/YC8w0yHh you can see that it works for your example data.

    EDIT

    If the assumption mentioned above does not hold, the following code will achieve the same result:

    <?php
    
    $data = array(
        array('id' => 1, 'title' => 'whatever'),
        array('id' => 2, 'title' => 'whatever'),
        array('id' => 3, 'title' => 'whatever')
    );
    
    $order = array(2,3,1);
    $order = array_flip($order);
    
    function cmp($a, $b)
    {
        global $order;
    
        $posA = $order[$a['id']];
        $posB = $order[$b['id']];
    
        if ($posA == $posB) {
            return 0;
        }
        return ($posA < $posB) ? -1 : 1;
    }
    
    usort($data, 'cmp');
    
    var_dump($data);
    

    See http://codepad.org/Q7EcTSfs for proof.

    By calling array_flip() on the $order array it can be used for position lookup. This is like a hashtable lookup, which is linear in time, or O(n). You cannot do better.

    0 讨论(0)
  • 2020-12-06 18:45

    You could try using a custom sort with usort(). This way you can use the first array to determine the order of the second array.

    0 讨论(0)
  • 2020-12-06 18:50

    For those of you who want to sort data based on an array with actual IDs, rather than based on an array with indexes like in the accepted answer - you can use the following simple comparison function for the usort:

    usort($data, function($a, $b) use ($order) {
        $posA = array_search($a['id'], $order);
        $posB = array_search($b['id'], $order);
        return $posA - $posB;
    });
    

    So the following example will work fine and you won't get the Undefined offset notices and an array with null values:

    $order = [20, 30, 10];
    
    $data = [
        ['id' => 10, 'title' => 'Title 1'],
        ['id' => 20, 'title' => 'Title 2'],
        ['id' => 30, 'title' => 'Title 3']
    ];
    
    usort($data, function($a, $b) use ($order) {
        $posA = array_search($a['id'], $order);
        $posB = array_search($b['id'], $order);
        return $posA - $posB;
    });
    
    echo '<pre>', var_dump($data), '</pre>';
    

    Output:

    array(3) {
      [0]=>
      array(2) {
        ["id"]=>
        int(20)
        ["title"]=>
        string(7) "Title 2"
      }
      [1]=>
      array(2) {
        ["id"]=>
        int(30)
        ["title"]=>
        string(7) "Title 3"
      }
      [2]=>
      array(2) {
        ["id"]=>
        int(10)
        ["title"]=>
        string(7) "Title 1"
      }
    }
    
    0 讨论(0)
  • 2020-12-06 18:51

    There is no built-in function for this in PHP and i am unable to think of any custom function, which would do this using usort. But array_map is simple enough, imo, so why not use it instead?

    $sorted = array_map(function($v) use ($data) {
        return $data[$v - 1];
    }, $order);
    
    0 讨论(0)
提交回复
热议问题