phparrayssortingcustom-sort

Custom sort on value prefix representing sizes (XXS, XS, S, M, L, XL, XXL)


I am currently trying to sort some clothing size arrays (S M L XL XXL etc.) that belong to an array. I am able to do this via the following function (thanks to this place Php Array Sorting Clothing Sizes (XXS XS S M L XL XXL) and Numbers on a Dynamic Array):

function cmp($a, $b) {
    
        $sizes = array(
        "XXS" => 0,
        "XS" => 1,
        "S" => 2,
        "M" => 3,
        "L" => 4,
        "XL" => 5,
        "XXL" => 6
        );
        
        $asize = $sizes[$a];
        $bsize = $sizes[$b];
        
        if ($asize == $bsize) {
            return 0;
        }
        
        return ($asize > $bsize) ? 1 : -1;
        
    }
    
    usort($the_array, "cmp");

This is all very well for an array that looks like this: $the_array("S", "M", "XL"). However, my array looks a bit like this:

$the_array = [
    "S : price £10",
    "XXL : price £10",
    "M : price £10",
    "XS : price £10"
];

This makes it not work. I need a function that ideally only looks at the first part of the array up to the ": ".


Solution

  • This solution will search the beginning of each string for the size values. It only works so long as no size is the prefix of another size, such as 'X' would be a prefix of 'XL'. It doesn't rely on the particular format of your data; it will find the earliest occurrence of a valid size string.

    // Your comparison function:
    function cmp($a, $b) {
      // Make the array static for performance.
      static $sizes = array('XXS', 'XS', 'S', 'M', 'L', 'XL', 'XXL');
    
      // Find the size of $a and $b (the first string for which strpos===0)
      $asize = 100; // Sort non-size strings after matching sizes.
      $apos = -1;
      $bsize = 100;
      $bpos = -1;
      foreach ($sizes AS $val => $str) {
        // It's important to use `===` because `==` will match on
        // FALSE, which is returns for no match.
        if (($pos = strpos($a, $str)) !== FALSE && ($apos < 0 || $pos < $apos)) {
          $asize = $val;
          $apos = $pos;
        }
        if (($pos = strpos($b, $str)) !== FALSE && ($bpos < 0 || $pos < $bpos)) {
          $bsize = $val;
          $bpos = $pos;
        }
      }
    
      return ($asize == $bsize ? 0 : ($asize > $bsize ? 1 : -1));
    }
    
    usort($the_array, 'cmp');