Array_Multisort and Dynamic Variable Options

array_multisort and dynamic variable options

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)

Dynamic array_multisort() without calling deprecated function create_function()

You can use an anonymous function instead:

$compare = function ($a, $b) use ($arguments, $c) {
return strcasecmp($a[$arguments[$c]], $b[$arguments[$c]]);
};

Untested but should be close enough

The use keyword allows you to inherit variables from the parent scope inside your function.

php array_multisort use array name as argument

You can call array_multisort() (or any other function) without specifying its arguments explicitly if you have the arguments in an array by using call_user_func_array().

array_multisort() gets its arguments by reference (in order to be able to modify them). You have to consider this when you build the array you use as argument to call_user_func_array() and put references in this array:

// Input arrays
$ar[1] = array("game", "scissors", "rock", "paper");
$ar[2] = array("D", "B", "A", "C");
$ar[3] = array("four", "two", "one", "three");

// Build the list of arguments for array_multisort()
// Use references to the arrays you want it to sort
$supar = array(&$ar[2], &$ar[1], &$ar[3]);

// Call array_multisort() indirectly
// This is the same as array_multisort($ar[2], $ar[1], $ar[3]);
call_user_func_array('array_multisort', $supar);

Check it in action: https://3v4l.org/ptiog

Why array_multisort doesn't sort in my case?

the array_multisort signature looks like this:

bool array_multisort ( array &$array1 [, mixed $array1_sort_order = SORT_ASC
[, mixed $array1_sort_flags = SORT_REGULAR [, mixed $... ]]] )

$sort_order and $sort_flags are two parameters, so instead of

$array, SORT_ASC | SORT_STRING

you need

$array, SORT_ASC, SORT_STRING

call_user_func_array with array_multisort

I had the same problem. It seems that call_user_func_array() can't handle the constants.
I've solved this problem by dynamically building an argument string and evaluating this string:

$args  = array($arr1, $arr2);
$order = array(SORT_ASC, SORT_DESC);
$evalstring = '';

foreach($args as $i=>$arg){
if($evalstring == ''){ $evalstring.= ', '; }
$evalstring.= '$arg';
$evalstring.= ', '.$order[$i];
}
eval("array_multisort($evalstring);");

I know eval() is evil and this is not a clean way, but it works ;-)

Sort array using array_multisort

OK, so, one of the first solutions that comes to mind is adding in the empty values to make them consistent:

function array_multisort_by_order(array $array, $by, array $order)
{
$max = max(array_map('count',$array));
//or, alternatively, depending on input (if there are no 'complete' subarrays):
//$max = max(array_map(function($arr){return max(array_keys($arr));},$array))+1;

//ADDITION: negative numeric keys:
$min = min(array_map(function($arr){return min(array_keys($arr));},$array));
$width = $max - min(0,$min);

foreach($array as &$sub){
// $addin = array_diff_key(array_fill(0,$max,null),$sub);
// $addin changed for negative keys:
$addin = array_diff_key(array_combine(range($min,$max),array_fill(0,$width,null)),$sub);
$sub = $addin + $sub;
ksort($sub);
}
$order = array_flip($order);
$params[] = $array[$by];
foreach($params[0] as &$v) $v = $order[$v];
foreach($array as &$v) $params[] = &$v; unset($v);
call_user_func_array('array_multisort', $params);
//no closeures here:
//foreach($array as &$sub) $sub = array_filter(function($a){return !is_null($a);},$sub);
$filter = create_function('$a','return !is_null($a);');
foreach($array as &$sub) $sub = array_filter($sub,$filter);
return $array;
}

Sort array of associative arrays on multiple columns using specified sorting rules

Here is what I finally settled on for being able to sort multi-dimensional arrays. Both of the answers above are good but I was also looking for something flexible.

I definitely don’t think there is any one “right” answer, but this is what works for my needs and is flexible.

As you can see from my @link in the comment of _usortByMultipleKeys() it was adapted from a comment in the PHP manual that currently doesn't seem to exist, but I believe http://www.php.net/manual/en/function.usort.php#104398 is a new version of the original comment. I have not explored using that new suggestion.

/**
* Sort the resultSet.
*
* Usage: $sortOptions = array(
* 'section', // Defaults to SORT_ASC
* 'row' => SORT_DESC,
* 'retail_price' => SORT_ASC);
* $results->sortResults($sortOptions);
*
* @param array $sortOptions An array of sorting instructions
*/
public function sortResults(array $sortOptions)
{
usort($this->_results, $this->_usortByMultipleKeys($sortOptions));
}

/**
* Used by sortResults()
*
* @link http://www.php.net/manual/en/function.usort.php#103722
*/
protected function _usortByMultipleKeys($key, $direction=SORT_ASC)
{
$sortFlags = array(SORT_ASC, SORT_DESC);
if (!in_array($direction, $sortFlags)) {
throw new InvalidArgumentException('Sort flag only accepts SORT_ASC or SORT_DESC');
}
return function($a, $b) use ($key, $direction, $sortFlags) {
if (!is_array($key)) { //just one key and sort direction
if (!isset($a->$key) || !isset($b->$key)) {
throw new Exception('Attempting to sort on non-existent keys');
}
if ($a->$key == $b->$key) {
return 0;
}
return ($direction==SORT_ASC xor $a->$key < $b->$key) ? 1 : -1;
} else { //using multiple keys for sort and sub-sort
foreach ($key as $subKey => $subAsc) {
//array can come as 'sort_key'=>SORT_ASC|SORT_DESC or just 'sort_key', so need to detect which
if (!in_array($subAsc, $sortFlags)) {
$subKey = $subAsc;
$subAsc = $direction;
}
//just like above, except 'continue' in place of return 0
if (!isset($a->$subKey) || !isset($b->$subKey)) {
throw new Exception('Attempting to sort on non-existent keys');
}
if ($a->$subKey == $b->$subKey) {
continue;
}
return ($subAsc==SORT_ASC xor $a->$subKey < $b->$subKey) ? 1 : -1;
}
return 0;
}
};
}


Related Topics



Leave a reply



Submit