我有两个多维数组,需要根据不同的键以与第二个数组相同的顺序对第一个数组进行排序(但它们的值相同)。在下面的示例中,我需要将
$allOptions
排序为与 $regOptions
相同的顺序,但基于 clID == optID
的值。
但是,并非所有
$allOptions
子数组 (clID) 都存在于 $regOptions
子数组 (optID) 中...因此,$allOptions
中的任何不匹配元素都将被扔到数组的底部/末尾数组。
我该怎么做?
$allOptions = array(
array("clID"=> 171, ...other values),
array("clID"=> 191, ...other values),
array("clID"=> 131, ...other values),
array("clID"=> 101, ...other values),
array("clID"=> 201, ...other values),
array("clID"=> 181, ...other values),
...
array("clID"=> 99, ...other values), // not in regOptions
array("clID"=> 129, ...other values) // not in regOptions
array("clID"=> 139, ...other values)
) ;
$regOptions = array(
array("order"=>1,"optID"=> 131, ...other values),
array("order"=>2,"optID"=> 191, ...other values),
array("order"=>3,"optID"=> 181, ...other values),
array("order"=>4,"optID"=> 139, ...other values),
array("order"=>5,"optID"=> 101, ...other values),
array("order"=>6,"optID"=> 201, ...other values),
array("order"=>7,"optID"=> 171, ...other values)
...
) ;
所以输出将是:
$allOptions = array(
array("clID"=> 131, ...other values),
array("clID"=> 191, ...other values),
array("clID"=> 181, ...other values),
array("clID"=> 139, ...other values)
array("clID"=> 101, ...other values),
array("clID"=> 201, ...other values),
array("clID"=> 171, ...other values),
...
array("clID"=> 99, ...other values), // not in regOptions
array("clID"=> 129, ...other values) // not in regOptions
) ;
所有之前发布的答案都太辛苦了。使用
array_column()
生成查找数组。使用 usort()
或 array_multisort()
按优先级数组排序。
代码:(演示)
$priority = array_column($regOptions, 'order', 'optID');
usort(
$allOptions,
fn($a, $b) => ($priority[$a['clID']] ?? PHP_INT_MAX) <=> ($priority[$b['clID']] ?? PHP_INT_MAX)
);
var_export($allOptions);
如果您想对所有未提及的 clId 值回退到按 clID ASC 排序,则使用 elvis 运算符通过对列值进行简单的三向比较来打破这些联系。
$priority = array_column($regOptions, 'order', 'optID');
usort(
$allOptions,
fn($a, $b) =>
($priority[$a['clID']] ?? PHP_INT_MAX) <=> ($priority[$b['clID']] ?? PHP_INT_MAX)
?: $a['clID'] <=> $b['clID']
);
第一个脚本可以通过以下方式使用
array_multisort()
执行。请注意,这种方法可能比 usort()
表现更好,因为它进行的查找次数更少,但它确实对 $priority
进行排序,然后对 clId
进行排序。 (演示)
$priority = array_column($regOptions, 'order', 'optID');
array_multisort(
array_map(fn($v) => $priority[$v['clID']] ?? PHP_INT_MAX, $allOptions),
$allOptions
);
var_export($allOptions);
使用 php usort()
示例
function customSort($a, $b, $regOptions) {
$aOptID = $a['clID'];
$bOptID = $b['clID'];
$aOrder = array_search($aOptID, array_column($regOptions, 'optID'));
$bOrder = array_search($bOptID, array_column($regOptions, 'optID'));
if ($aOrder === false) $aOrder = PHP_INT_MAX;
if ($bOrder === false) $bOrder = PHP_INT_MAX;
return $aOrder - $bOrder;
}
usort($allOptions, function($a, $b) use ($regOptions) {
return customSort($a, $b, $regOptions);
});
这是一个不基于
array_search()
的解决方案:
$allOptions = [["clID" => 1], ["clID" => 2], ["clID" => 3], ["clID" => 4]];
$regOptions = [["optID" => 3], ["optID" => 2]];
$order = [];
foreach($regOptions as $key => $option)
$order[$option['optID']] = $key;
usort($allOptions, function($o1, $o2) use($order)
{
$id1 = $o1['clID'];
$id2 = $o2['clID'];
if(isset($order[$id1]) && isset($order[$id2]))
return $order[$id1] <=> $order[$id2];
if(isset($order[$id1]) && !isset($order[$id2]))
return -1;
if(!isset($order[$id1]) && isset($order[$id2]))
return 1;
return $id1 <=> $id2;
});
var_export($allOptions);
结果:
array (
0 =>
array (
'clID' => 3,
),
1 =>
array (
'clID' => 2,
),
2 =>
array (
'clID' => 1,
),
3 =>
array (
'clID' => 4,
),
)
排序的另一个选项是迭代
$regOptions
并从 $indexedOptions
构建一个新数组,然后将未找到的任何项目附加到末尾。现场示例https://3v4l.org/jd5Rq
<?php
$allOptions = array(
array("clID"=> 171),
array("clID"=> 191),
array("clID"=> 131),
array("clID"=> 101),
array("clID"=> 201),
array("clID"=> 181),
array("clID"=> 99), // not in regOptions
array("clID"=> 129), // not in regOptions
array("clID"=> 139),
) ;
$regOptions = array(
array("order"=>1,"optID"=> 131),
array("order"=>2,"optID"=> 191),
array("order"=>3,"optID"=> 181),
array("order"=>4,"optID"=> 139),
array("order"=>5,"optID"=> 101),
array("order"=>6,"optID"=> 201),
array("order"=>7,"optID"=> 171)
);
// build new array from original array with indexes for faster lookups
$indexedOptions = [];
foreach($allOptions as $val) {
$indexedOptions[$val['clID']] = $val;
}
$newArray = [];
foreach ($regOptions as $order) {
$id = $order['optID'];
if (isset($indexedOptions[$id])) {
$newArray[] = $indexedOptions[$id];
unset($indexedOptions[$id]);
}
}
// at this point, $newArray has all of the found values in order,
// and $indexedOptions has any remaining items.
// var_dump($newArray);
// var_dump($indexedOptions);
// put them together for the final array
$final = array_merge($newArray, $indexedOptions);
var_dump($final);
输出:
array(9) {
[0]=> array(1) {
["clID"]=> int(131)
}
[1]=> array(1) {
["clID"]=> int(191)
}
[2]=> array(1) {
["clID"]=> int(181)
}
[3]=> array(1) {
["clID"]=> int(139)
}
[4]=> array(1) {
["clID"]=> int(101)
}
[5]=> array(1) {
["clID"]=> int(201)
}
[6]=> array(1) {
["clID"]=> int(171)
}
[7]=> array(1) {
["clID"]=> int(99)
}
[8]=> array(1) {
["clID"]=> int(129)
}
}