Home » Php » arrays – PHP sort by arbitrary order

arrays – PHP sort by arbitrary order

Posted by: admin July 12, 2020 Leave a comment

Questions:

I need a function in php to sort a list of words according to an arbitrary ordering.

Any words in the list not in my predefined order should be sorted alphabetically at the end of the list.

Below is my first attempt, it is neither elegant or efficient. Can you suggest a better way to acheive this?

Thanks

public static function sortWords(&$inputArray){
    $order=array("Banana","Orange", "Apple", "Kiwi");
    sort($inputArray);
    for($i=0;$i<count($inputArray));$i++){
        $ac = $inputArray[$i];
        $position = array_search($ac,$order);
        if($position !== false && $i != $position){
            $temp=$inputArray[$position];
            $inputArray[$position]=$inputArray[$i];
            $inputArray[$i]=$temp;
        }
    }
}
How to&Answers:

PHP provides the usort() and uksort() functions to allow you to write your own sorting routines. Of these two, you’ll be wanting usort().

Both these functions expect you to write a stand-alone function, which takes as input two elements of the input array, and returns the order that they should be sorted into. The usort() function then runs its own sorting algorithm, calling your function as to establish the sorting order often as required until it has sorted the entire array.

So you’d write something like this….

function mycompare($a, $b) {
    if ($a == $b) {return 0;}
    $order=array("Banana","Orange", "Apple", "Kiwi");
    $position = array_search($a,$order);
    $position2 = array_search($b, $order);

    //if both are in the $order, then sort according to their order in $order...
    if ($position2!==false && $position!==false) {return ($position < $position2) ? -1 : 1;}
    //if only one is in $order, then sort to put the one in $order first...
    if($position!==false) {return -1;}
    if($position2!==false) {return 1;}

    //if neither in $order, then a simple alphabetic sort...
    return ($a < $b) ? -1 : 1;
}

…then just call usort($inputarray,'mycompare'); to sort them.

Answer:

public static function sortWords($inputArray){
    $order=array("Banana","Orange", "Apple", "Kiwi");
    $sorted_array = array_diff($inputArray,$order);
    sort($sorted_array);
    $rest_array = array_intersect($order,$inputArray);    
    $result = array_merge($rest_array,$sorted_array);
    return $result;
}

Haven’t tested but try this.

Answer:

Probably slower than Headshota’s solution, but just to provide you another (not tested) possibility:

function sortWordsCmp($a, $b) {
  $order=array("Banana","Orange", "Apple", "Kiwi");
  $a = array_search($a, $order);
  $b = array_search($b, $order);

  if ($a === $b)
    return 0;

  return (($b===false) || ($a < $b)) ? -1 : +1;
}

public static function sortWords($inputArray){
  usort($inputArray, 'sortWordsCmp');
  return $inputArray;
}

Answer:

public static function sortByArbitraryKeys(&$inputArray, $sort_order) {
    $sort_order = array_flip($sort_order);
    uksort($inputArray, function ($a, $b) use ($sort_order) {
        return $sort_order[$a] - $sort_order[$b];
    }
}

So an example would be the following…

// Doe, John L.
$this->full_name = ['last_name'=>'Doe', 'first_name'=>'John', 'middle_initial'=>'L.'];

// John L. Doe
$this->sortByArbitraryKeys($this->full_name, ['first_name', 'middle_initial', 'last_name']);

You could easily refactor this for whatever your specific use case is.