使用 array_multisort() 和动态数量的参数/参数/规则/数据对数组进行排序

发布于 2024-08-25 07:49:33 字数 483 浏览 6 评论 0原文

我正在尝试使用 array_multisort() 对任何数组进行排序,一切正常。但是,根据脚本中的条件,我需要更改选项。

到目前为止我所拥有的是:

array_multisort(
    $sort1,
    SORT_ASC,
    $sort2,
    SORT_ASC,
    $sort3,
    SORT_ASC, 
    $arraytosort
);

我想写一些东西,允许更灵活/动态的有效负载排序数据/规则。像这样的事情:

$dynamicSort = "$sort1,SORT_ASC,$sort2,SORT_ASC,$sort3,SORT_ASC,";

array_multisort(
    $dynamicSort, 
    $arraytosort
);

如何向 array_multisort() 提供未知数量的参数并让它修改 $arraytosort 数组?

I'm 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.

What I have so far is this:

array_multisort(
    $sort1,
    SORT_ASC,
    $sort2,
    SORT_ASC,
    $sort3,
    SORT_ASC, 
    $arraytosort
);

I would like to write something that will allow a more flexible/dynamic payload of sorting data/rules. Something like this:

$dynamicSort = "$sort1,SORT_ASC,$sort2,SORT_ASC,$sort3,SORT_ASC,";

array_multisort(
    $dynamicSort, 
    $arraytosort
);

How can I feed an unknown number of parameters to array_multisort() and have it modify the $arraytosort array?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

小矜持 2024-09-01 07:49:33

您可以尝试使用 call_user_func_array。但我以前从未在内置函数上尝试过它。这是一个例子:

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

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)
云朵有点甜 2024-09-01 07:49:33

我对这个答案也有同样的问题:“参数#1应该是一个数组或排序标志”

对于任何有同样问题的人,请尝试这个:

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

请注意,我已经使用了对我的变量“&$”的引用美元。
这在 php 5.3 中效果很好,但在 5.2 中可能会由于错误而导致错误。

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.

南冥有猫 2024-09-01 07:49:33

重要的是要理解发送到 call_user_func_array() 的数组必须包含引用;数组本身是否通过引用传递并不重要。我花了一天的大部分时间来解决这个问题;事实上 php.net 函数页面上的示例都使用了文字数组,这让我看到了这个页面: php 错误#49353。问题解决了。

这似乎没有很好(或一致)记录,所以这里......

这些不起作用(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

这些起作用:

$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

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
一片旧的回忆 2024-09-01 07:49:33

从 PHP5.6 开始,您可以使用可变参数技术。只需将所有排序数据和排序逻辑推送到索引数组中,然后使用 splat 运算符将参数解压到 array_multisort() 中。确保将要修改的数组设置为可通过引用进行修改,然后再将其推入参数数组。

下面将参数推入 $sortingParams 可以更简洁地编写为单个声明,但我认为这种方式更容易概念化。这些单独的推送适用于迭代过程(例如foreach())。

对于用于对父数组进行排序的每一列数据,您可以选择推送零个、一个或两个附加元素,以最好地表示排序逻辑。

代码:(演示)

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

输出:

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,
  ),
)

如果您将动态规则传递到进程,则此技术非常强大。就我而言,我需要从 DataTables UI 收集过滤器并将数据重新生成为 .csv。我只需要迭代 DataTable 的订单数据并导出我的规则集 - 完成。

我发现这种语法比 call_user_func_array() 更舒服。

这是一个更复杂的实现:使用指定的排序规则对多个列上的关联数组进行排序

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

挽清梦 2024-09-01 07:49:33

为了添加现有的答案,我只是想添加一些东西。对于任何将所需的“排序依据”作为逗号分隔的 $_POST 变量(或任何与此相关的逗号分隔变量)传递的人:

//$_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);

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);
稚然 2024-09-01 07:49:33

我正在尝试做一件非常相似的事情,但由于我的 $sort 数组也是动态创建的,所以我选择了稍微不同的方法:
输入时我得到两个数组 $sortColumns$sortDirections

$sortColumnsArrayColumn = array_map(
    function ($n) use ($mainArray) {
        return array_column($mainArray, $n);
    }, $sortColumns
); //creates "$sort" arrays
                
$columnsAndDirections = array_map(null, $sortColumnsArrayColumn, $sortDirections); // zip both arrays together
$params = array_merge(...$columnsAndDirections); // flatten zipped array
$params[] = &$mainArray; // add reference to the mainArray
array_multisort(...$params);

但我仍然收到警告消息,并且不知道如何更改:“Warning: array_multisort(): Argument # 2 预计是一个数组或排序标志”


编辑:原来我的 $sortDirections 数组包含字符串,而不是 PHP 常量。改变它解决了这个问题;)

I'm trying to do a very similar thing, but as my $sort arrays are also created dynamically, I opted for a slightly different approach:
on input I get two arrays $sortColumns and $sortDirections

$sortColumnsArrayColumn = array_map(
    function ($n) use ($mainArray) {
        return array_column($mainArray, $n);
    }, $sortColumns
); //creates "$sort" arrays
                
$columnsAndDirections = array_map(null, $sortColumnsArrayColumn, $sortDirections); // zip both arrays together
$params = array_merge(...$columnsAndDirections); // flatten zipped array
$params[] = &$mainArray; // add reference to the mainArray
array_multisort(...$params);

I still get the warning message though, and not sure how to change that: "Warning: array_multisort(): Argument #2 is expected to be an array or a sort flag"


EDIT: Turned out my $sortDirections array contained strings, not PHP constants. Changing that solved the issue ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文