• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • uasort()

    (PHP 4, PHP 5, PHP 7)

    使用用户自定义的比较函数对数组中的值进行排序并保持索引关联

    说明

    uasort(array &$array,callable$value_compare_func): bool

    本函数对数组排序并保持索引和单元之间的关联。

    主要用于对那些单元顺序很重要的结合数组进行排序。比较函数是用户自定义的。

    Note:

    If two members compare as equal, their relative order in the sorted array is undefined.

    参数

    $array

    输入的数组。

    $value_compare_func

    用户自定义比较函数的例子请参考usort()和uksort()。

    返回值

    成功时返回TRUE,或者在失败时返回FALSE

    范例

    Example #1uasort()的基本例子

    <?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);
    ?>
    

    以上例程会输出:

    Array
    (
        [a] => 4
        [b] => 8
        [c] => -1
        [d] => -9
        [e] => 2
        [f] => 5
        [g] => 3
        [h] => -4
    )
    Array
    (
        [d] => -9
        [h] => -4
        [c] => -1
        [e] => 2
        [g] => 3
        [a] => 4
        [f] => 5
        [b] => 8
    )
    

    参见

    • usort() 使用用户自定义的比较函数对数组中的值进行排序
    • 数组排序函数对比
    a quick reminder on the syntax if you want to use uasort in a Class or Object:
    <?php
    // procedural:
    uasort($collection, 'my_sort_function');
    // Object Oriented
    uasort($collection, array($this, 'mySortMethod'));
    // Objet Oriented with static method
    uasort($collection, array('self', 'myStaticSortMethod'));
    ?>
    
    If you want to keep the order when two members compare as equal, use this.
    <?php
    function stable_uasort(&$array, $cmp_function) {
      if(count($array) < 2) {
        return;
      }
      $halfway = count($array) / 2;
      $array1 = array_slice($array, 0, $halfway, TRUE);
      $array2 = array_slice($array, $halfway, NULL, TRUE);
      stable_uasort($array1, $cmp_function);
      stable_uasort($array2, $cmp_function);
      if(call_user_func($cmp_function, end($array1), reset($array2)) < 1) {
        $array = $array1 + $array2;
        return;
      }
      $array = array();
      reset($array1);
      reset($array2);
      while(current($array1) && current($array2)) {
        if(call_user_func($cmp_function, current($array1), current($array2)) < 1) {
          $array[key($array1)] = current($array1);
          next($array1);
        } else {
          $array[key($array2)] = current($array2);
          next($array2);
        }
      }
      while(current($array1)) {
        $array[key($array1)] = current($array1);
        next($array1);
      }
      while(current($array2)) {
        $array[key($array2)] = current($array2);
        next($array2);
      }
      return;
    }
    function cmp($a, $b) {
      if($a['n'] == $b['n']) {
        return 0;
      }
      return ($a['n'] > $b['n']) ? -1 : 1;
    }
    $a = $b = array(
      'a' => array("l" => "A", "n" => 1),
      'b' => array("l" => "B", "n" => 2),
      'c' => array("l" => "C", "n" => 1),
      'd' => array("l" => "D", "n" => 2),
      'e' => array("l" => "E", "n" => 2),
    );
    uasort($a, 'cmp');
    print_r($a);
    stable_uasort($b, 'cmp');
    print_r($b);
    ?>
    returns
    Array
    (
      [e] => Array
        (
          [l] => E
          [n] => 2
        )
      [b] => Array
        (
          [l] => B
          [n] => 2
        )
      [d] => Array
        (
          [l] => D
          [n] => 2
        )
      [c] => Array
        (
          [l] => C
          [n] => 1
        )
      [a] => Array
        (
          [l] => A
          [n] => 1
        )
    )
    Array
    (
      [b] => Array
        (
          [l] => B
          [n] => 2
        )
      [d] => Array
        (
          [l] => D
          [n] => 2
        )
      [e] => Array
        (
          [l] => E
          [n] => 2
        )
      [a] => Array
        (
          [l] => A
          [n] => 1
        )
      [c] => Array
        (
          [l] => C
          [n] => 1
        )
    )
    https://bugs.php.net/bug.php?id=53341
    An Example using anonymous function.
    Anonymous functions make some time the code easier to understand.
    <?php
    $fruits = array('Orange9','Orange11','Orange10','Orange6','Orange15');
    uasort ( $fruits , function ($a, $b) {
          return strnatcmp($a,$b); // or other function/code
        }
      );
    print_r($fruits);
    ?>
    returns
    Array
    (
      [3] => Orange6
      [0] => Orange9
      [2] => Orange10
      [1] => Orange11
      [4] => Orange15
    )
    User "php at clement dot hk" already provided a stable uasort function, but I find this wrapper much shorter and easier to understand:
    https://github.com/vanderlee/PHP-stable-sort-functions/blob/master/classes/StableSort.php
    function stable_uasort(array &$array, $value_compare_func) {
      $index = 0;
      foreach ($array as &$item) {
        $item = array($index++, $item);
      }
      $result = uasort($array, function($a, $b) use($value_compare_func) {
        $result = call_user_func($value_compare_func, $a[1], $b[1]);
        return $result == 0 ? $a[0] - $b[0] : $result;
      });
      foreach ($array as &$item) {
        $item = $item[1];
      }
      return $result;
    }
    Difference between uasort() and usort(), the missing example ...
    <?php
     $arr = array ( 10 => array('id' => 'dix', 'aa' => '1010'),
            100 => array('id' => 'cent', 'aa' => '100100'),
             2 => array('id' => 'deux', 'aa' => '22'), 
             7 => array('id' => 'sept', 'aa' => '77'));
     // id sorting
     function so ($a, $b) { return (strcmp ($a['id'],$b['id']));  }
    ?>
    *** uasort($arr, 'so') output:
    <?php Array (
      [100] => Array
        (
          [id] => cent
          [aa] => 100100
        )
      [2] => Array
        (
          [id] => deux
          [aa] => 22
        )
      [10] => Array
        (
          [id] => dix
          [aa] => 1010
        )
      [7] => Array
        (
          [id] => sept
          [aa] => 77
        ))?>
    *** usort($arr, 'so') output:
    <?php Array (
      [0] => Array
        (
          [id] => cent
          [aa] => 100100
        )
      [1] => Array
        (
          [id] => deux
          [aa] => 22
        )
      [2] => Array
        (
          [id] => dix
          [aa] => 1010
        )
      [3] => Array
        (
          [id] => sept
          [aa] => 77
        ))?>
    
    //this fix the problem of if any of these sort functions evaluates two members as equal then the order is undefined (the sorting is not stable).
    $pos=0;
    foreach($values as $k => $v)
     $tosort[$k]=array($v,$pos++);
    uasort($tosort,function($a, $b) {
     if($a[0] != $b[0])return ($a[0] < $b[0]) ? -1 : 1;
      return ($a[1] < $b[1]) ? -1 : 1;}
    );
    foreach($tosort as $k => $v)
     $values[$k]=$v[0];
    I tried using some of the previous built multisorts, but they weren't working as expected.
    So, I made my own Class, and it seems to work wonderfully.
    Here is the code:
    <?php
    /************************************
    *  Allows sorting multi-dimensional
    *  arrays by a specific key and in
    *  asc or desc order
    **/
    class multiSort
    {
      var $key;  //key in your array
      //runs the sort, and returns sorted array
      function run ($myarray, $key_to_sort, $type_of_sort = '')
      {
        $this->key = $key_to_sort;
        
        if ($type_of_sort == 'desc')
          uasort($myarray, array($this, 'myreverse_compare'));
        else
          uasort($myarray, array($this, 'mycompare'));
          
        return $myarray;
      }
      
      //for ascending order
      function mycompare($x, $y)
      {
        if ( $x[$this->key] == $y[$this->key] )
          return 0;
        else if ( $x[$this->key] < $y[$this->key] )
          return -1;
        else
          return 1;
      }
      
      //for descending order
      function myreverse_compare($x, $y)
      {
        if ( $x[$this->key] == $y[$this->key] )
          return 0;
        else if ( $x[$this->key] > $y[$this->key] )
          return -1;
        else
          return 1;
      }
    }
    ?>
    
    To shuffle assoc array preserving keys just do this:
    <?php uasort(
      $array,
      function ($a, $b) {
        return mt_rand(0, 1) > 0 ? 1 : -1;
      }
    ); ?>
    
    Use example:
    $array[0]['Fator1']=7;
    $array[0]['Fator2']="Name";
    $array[1]['Fator1']=5;
    $array[1]['Fator2']="Name";
    $array[2]['Fator1']=7;
    $array[2]['Fator2']="NameDiferente";
    .....
    We want to order by Fator1, then Fator2, then:
    function Compare($ar1, $ar2)
    {
      if ($ar1['Fator1']<$ar2['Fator1'])
       return -1;
      else if ($ar1['Fator1']>$ar2['Fator1'])
       return 1;
      if ($ar1['Fator2']<$ar2['Fator2'])
       return -1;
      else if ($ar1['Fator2']>$ar2['Fator2'])
       return 1;
      return 0;
    }
    To sort now, we use:
    uasort($array, 'Compare');
    Is it just me, or are the examples below misleading, and actually demonstrating situations that would be more appropriate for usort()?
    After trying to make sense of the uasort() description, it sounds like it's more for sorting a 1D array like this:
    "john" => "$23.12"
    "tim" => "$6.50"
    "bob" => "$18.54"
    and getting back:
    "tim" => "$6.50"
    "bob" => "$18.54"
    "john" => $23.12"
    (assuming, of course, that your sort function is lopping off the $ and evaluating as a number -- which would complicate the use of asort() ;)
    Keep in mind that PHP sorting functions are not reliable to handle "stable sorting", even since PHP7+.
    It might work on small arrays, but not on "big" ones (100 items are enough for the stable sorting to fail).
    <?php
    $a = array_fill(0, 100, 'foo');
    $b = $a;
    var_dump($b === $a); // bool(true)
    uasort($a, function () {
      return 0; // Consider all items are the same
    });
    var_dump($b === $a); // bool(false)
    ?>
    To ensure $b === $a, use a 3rd-party stable sorting function:
    http://php.net/manual/en/function.uasort.php#121283
    My simple and effective solution for sort multi-dimensional array by any key:
    <?php
    function sort_by_key ($arr,$key) {
      global $key2sort;
      $key2sort = $key;
      uasort($arr, 'sbk');
      return ($arr);
    }
    function sbk ($a, $b) {global $key2sort; return (strcasecmp ($a[$key2sort],$b[$key2sort]));}
    ?>
    
    Just expanding on php arobase kochira period com's method:
    If you are looking to sort a multi-D array by a specific column and have entries in both upper and lower case, simply drop the entries to lowercase before doing the strcmp.
    <?php
    $dirs = array(
     array('name' => 'First Folder', 'path' => 'sompath'),
     array('name' => 'second folder', 'path' => 'sompath2'),
     array('name' => 'Third Folder', 'path' => 'sompath3')
    );
    function so($a, $b) { 
      return (strcmp (strtolower($a['name']), strtolower($b['name'])));
    }
    ?>
    
    Here is a little sort function that actually uses a dynamic callback for usort to do it's thing.
    It assumes your data is in the form of:
      $data = array(
          array('ID'=>'6','LAST'=>'Holmes','FIRST'=>'Dan'),
          array('ID'=>'1234','LAST'=>'Smith','FIRST'=>'Agent K'),
          array('ID'=>'2','LAST'=>'Smith','FIRST'=>'Agent J'),
          array('ID'=>'4','LAST'=>'Barney','FIRST'=>'Bob'));
    Now, you want to sort on one or more cols, don't you? 
    masort($data, 'LAST,FIRST');
    or 
    masort($data,array('FIRST','ID'));
    Of course you could add a bunch to it (like numeric comparison if appropriate, desc/asc, etc) but it works for me.
    function masort(&$data, $sortby){
      if(is_array($sortby)){
        $sortby = join(',',$sortby);
      }
      uasort($data,create_function('$a,$b','$skeys = split(\',\',\''.$sortby.'\');
        foreach($skeys as $key){
          if( ($c = strcasecmp($a[$key],$b[$key])) != 0 ){
            return($c);
          }
        }
        return($c); '));
    }
    Notice that I am splitting the string in the comparison function? While this is certainly slower, it was the only way I would find to "pass" and "array". If anyone has a better way, please suggest. Then inside, we (string) compare the values only moving to the next key if the values are the same...and so on, and so on.
    // Anonumous functions
    uasort($collection, array($this, function($a, $b){
       //logic
    }));
    You can sort a multidimensionnal array by any of its key with this function:
    function multi_sort($array, $key)
    {
     $cmp_val="((\$a['$key']>\$b['$key'])?1:
      ((\$a['$key']==\$b['$key'])?0:-1))";
     $cmp=create_function('$a, $b', "return $body;");
     uasort($array, $cmp);
     return $array;
    }
    example:
    $myarray = array(
     array("name"=>"kernighan", "language"=>"c"),
     array("name"=>"lerdorf", "language"=>"php"),
     array("name"=>"Stroustrup", "language"=>"c++"),
     array("name"=>"Gosling", "language"=>"java")
    );
    multi_sort($myarray, "name") returns:
    name=Gosling  language=java
    name=Kernighan  language=c
    name=Lerdorf  language=php
    name=Stroustrup  language=c++

    上篇:sort()

    下篇:uksort()