array_multisort and dynamic variable options

前端 未结 5 832
孤独总比滥情好
孤独总比滥情好 2020-11-27 08:53

Im trying to sort any array with array_multisort and everything is working great. However, based on conditions in my script, I need to change the options. So What I have s

相关标签:
5条回答
  • 2020-11-27 09:03

    You could try to use call_user_func_array. But I've never tried it on a built-in function before. Here is an example:

    $dynamicSort = "$sort1,SORT_ASC,$sort2,SORT_ASC,$sort3,SORT_ASC";
    $param = array_merge(explode(",", $dynamicSort), array($arrayToSort))
    call_user_func_array('array_multisort', $param)
    
    0 讨论(0)
  • 2020-11-27 09:07

    I had the same problem with this answer: "Argument #1 is expected to be an array or a sort flag"

    For anyone having the same problem try this instead:

    $dynamicSort = array(&$sort1, SORT_ASC, &$sort2, SORT_ASC, &$sort3, SORT_ASC); 
    $param = array_merge($dynamicSort, array(&$arrayToSort));
    call_user_func_array('array_multisort', $param);
    

    Note that i have used the reference to my variables "&$" instead of $. This works great in php 5.3 but may cause error in 5.2 due to a bug.

    0 讨论(0)
  • 2020-11-27 09:12

    It is important to understand that the array sent to call_user_func_array() must consist only of references; it is not important whether the array itself is passed by reference. I spent the better part of a day troubleshooting this; the fact that the examples on the function page at php.net all used literal arrays led me to this page: php Bug #49353. Problem solved.

    This doesn't seem to be very well (or consistently) documented, so here goes....

    These DO NOT WORK (PHP 5.3.3):

    $multisort_array = array($arr1, SORT_DESC, SORT_STRING, $arr2);      // array of values
    call_user_func_array('array_multisort', $multisort_array);           // array passed by value
    
    $multisort_array = array($arr1, SORT_DESC, SORT_STRING, $arr2);      // array of values
    call_user_func_array('array_multisort', &$multisort_array);          // array passed by reference
    
    $multisort_array = array(&$arr1, SORT_DESC, SORT_STRING, &$arr2);    // non-constants by reference
    call_user_func_array('array_multisort', $multisort_array);           // array passed by value
    
    $multisort_array = array(&$arr1, SORT_DESC, SORT_STRING, &$arr2);    // non-constants by reference
    call_user_func_array('array_multisort', &$multisort_array);          // array passed by reference
    

    These DO WORK:

    $sort = array('desc' => SORT_DESC, 'string' => SORT_STRING);
    $multisort_array = array(&$arr1, &$sort['desc'], &$sort['string'], &$arr2);      // all by reference
    call_user_func_array('array_multisort', $multisort_array);                       // array passed by value
    
    $sort = array('desc' => SORT_DESC, 'string' => SORT_STRING);
    $multisort_array = array(&$arr1, &$sort['desc'], &$sort['string'], &$arr2);      // all by reference
    call_user_func_array('array_multisort', &$multisort_array);                      // array passed by reference
    
    0 讨论(0)
  • 2020-11-27 09:13

    From PHP5.6, you can use a variadic technique. Simply push all of your sorting data and sorting logic into an indexed array, then use the splat operator to unpack the parameters into array_multisort(). Be sure to make the array that you wish to modify -- modifiable by reference before pushing it into the parameters array.

    The pushing of parameters into $sortingParams below can be written more succinctly as a single declaration, but I think it will be easier to conceptualize this way. These individual pushes would be suitable inside of an iterating process (e.g. foreach()).

    For every column of data used to sort the parent array, you may elect to push zero, one, or two additional elements to best signify the sorting logic.

    Code: (Demo)

    $array = [
        ['number' => 2, 'letter' => 'a', 'price' => 9.99], 
        ['number' => 3, 'letter' => 'b', 'price' => 9.99], 
        ['number' => 1, 'letter' => 'c', 'price' => 9.50],
        ['number' => 1, 'letter' => 'd', 'price' => 10],
        ['number' => 1, 'letter' => 'e', 'price' => 9.99],
    ];
    
    $sortingParams[] = array_column($array, 'number');  // 1-dimensional
    $sortingParams[] = SORT_ASC;                        // this is omittable as well because it is assumed (just for demo)
    $sortingParams[] = array_column($array, 'price');   // 1-dimensional
    $sortingParams[] = SORT_DESC;
    $sortingParams[] = SORT_NUMERIC;                    // this is omittable as well because it is assumed (just for demo)
    $sortingParams[] = &$array;                         // this is the actual master array which should be modified
    
    array_multisort(...$sortingParams);                 // unpack with splat operator
    var_export($array);
    

    Output:

    array (
      0 => 
      array (
        'number' => 1,
        'letter' => 'd',
        'price' => 10,
      ),
      1 => 
      array (
        'number' => 1,
        'letter' => 'e',
        'price' => 9.99,
      ),
      2 => 
      array (
        'number' => 1,
        'letter' => 'c',
        'price' => 9.5,
      ),
      3 => 
      array (
        'number' => 2,
        'letter' => 'a',
        'price' => 9.99,
      ),
      4 => 
      array (
        'number' => 3,
        'letter' => 'b',
        'price' => 9.99,
      ),
    )
    

    This technique is super powerful if you have dynamic rules being passed to your process. In my case, I needed to collect filters from my DataTables UI and regenerate the data as a .csv. I merely needed to iterate through DataTable's order data and derive my set of rules - done.

    I find this syntax much kinder on the eyes versus call_user_func_array().

    Here is a more complex implementation: Sort array of associative arrays on multiple columns using specified sorting rules

    0 讨论(0)
  • 2020-11-27 09:26

    To add onto the existing answers, just thought I would add a little something. For anyone passing the desired "sort by" as a comma-separated $_POST variable (or any comma-separated variable for that matter):

    //$_POST["sort_by"] = "column_A DESC, column_B ASC, columns_C DESC";
    $sort_bys = explode(",", $_POST["sort_by"]);
    $dynamicSort = array();
    foreach($sort_bys as $sort_by){
        $sort_by2 = trim(str_replace('DESC','',$sort_by));
        $direction = (strpos($sort_by, 'DESC') !== false)?SORT_DESC:SORT_ASC;
        $$sort_by2  = array_column($array_to_sort, $sort_by2);
        $dynamicSort[] = &$$sort_by2;
        $dynamicSort[] = $direction;
        $dynamicSort[] = SORT_NUMERIC; //or SORT_STRING or SORT_REGULAR ...
    }    
    $param = array_merge($dynamicSort, array(&$array_to_sort));
    call_user_func_array('array_multisort', $param);
    
    0 讨论(0)
提交回复
热议问题