phparrayssortingincrementdense-rank

Add order column to array to indicate rank from oldest to youngest


In PHP7, If I have this array:

$array = [
    ["name" => "Jon", "age" => 44],
    ["name" => "Bob", "age" => 32],
    ["name" => "Jim", "age" => 103],
    ["name" => "Ted", "age" => 19]
];

What is the most elegant way to process this array to add an extra column indicating who is the oldest to who is the youngest like so...

[
    ["name" => "Jon", "age" => 44, "order" => 2],
    ["name" => "Bob", "age" => 32, "order" => 3],
    ["name" => "Jim", "age" => 103, "order" => 1],
    ["name" => "Ted", "age" => 19, "order" => 4]
]

Solution

  • Without a point of reference to determine which is the oldest user you're stuck either doing a multi loop comparison or a sort then insert.

    A Multi loop comparasin would look something like

    <?php
    $array = [
      ["name" => "Jon", "age" => 44],
      ["name" => "Bob", "age" => 32],
      ["name" => "Jim", "age" => 103],
      ["name" => "Ted", "age" => 19]
    ];
    
    $count = count($array);
    
    for($index = 0; $index < $count; ++$index) {
      $order = 1;
      $age = $array[$index]["age"];
      for($index2 = 0; $index2 < $count; ++$index2) {
        if($array[$index2]["age"] > $age) {
          ++$order;
        }
      }
    
      $array[$index]["order"] = $order;
    }
    
    echo "<pre>";
    var_dump($array);
    echo "</pre>";
    

    Sort then insert would involve array_walk and uasort

    From the docs

    <?php
    $fruits = array("d" => "lemon", "a" => "orange", "b" => "banana", "c" => "apple");
    
    function test_alter(&$item1, $key, $prefix)
    {
      $item1 = "$prefix: $item1";
    }
    
    function test_print($item2, $key)
    {
      echo "$key. $item2<br />\n";
    }
    
    echo "Before ...:\n";
    array_walk($fruits, 'test_print');
    
    array_walk($fruits, 'test_alter', 'fruit');
    echo "... and after:\n";
    
    array_walk($fruits, 'test_print');
    

    and docs

    <?php
    // Comparison function
    function cmp($a, $b) {
      if ($a == $b) {
        return 0;
      }
      return ($a < $b) ? -1 : 1;
    }
    
    // Array to be sorted
    $array = array('a' => 4, 'b' => 8, 'c' => -1, 'd' => -9, 'e' => 2, 'f' => 5, 'g' => 3, 'h' => -4);
    print_r($array);
    
    // Sort and print the resulting array
    uasort($array, 'cmp');
    print_r($array);
    

    so for your example it would be something like this:

    <?php
    function walkFunc(&$item, $key) {
      $item["order"] = $key + 1;
    }
    
    // as @waterloomatt mentioned the Spaceship operator is meant for this
    function sortComp($a, $b) {
      return ($a["age"] <=> $b["age"]) * -1;
    }
    
    $array = [
      ["name" => "Jon", "age" => 44],
      ["name" => "Bob", "age" => 32],
      ["name" => "Jim", "age" => 103],
      ["name" => "Ted", "age" => 19]
    ];
    
    uasort($array, 'sortComp');
    array_walk($array, 'walkFunc');
    
    echo "<pre>";
    var_dump($array);
    echo "</pre>";