3 回答
TA贡献1809条经验 获得超8个赞
看起来你想要的东西很难用 PHP 的排序方法之一实现。此外,由于不匹配键的相对顺序不应该改变,我们可以争取比 O (nlogn)排序方法更好的时间复杂度。
因此,我建议编写一个函数,对两个数组 ( $array, $order) 进行一些迭代,以便按预期顺序收集键/值对。这构成了O(n+m)时间复杂度,其中n和m是两个数组的两个大小。
这是功能:
function sortadjacent($array, $order) {
$insertAt = 0;
foreach($array as $key => $_) {
if (isset($order[$key])) break;
$insertAt++;
}
$special = [];
foreach($order as $key => $_) {
if (isset($array[$key])) $special[$key] = $array[$key];
}
$result = [];
foreach($array as $key => $value) {
if (!isset($order[$key])) $result[$key] = $value;
else if (count($result) == $insertAt) $result = array_merge($result, $special);
}
return $result;
}
你会这样称呼它:
$result = sortadjacent($array, $order);
请注意,此函数不会对 进行更改$array,而是在新数组中返回预期结果。
TA贡献1829条经验 获得超13个赞
您的实现非常接近,但是您必须在比较函数中考虑这种情况,其中只有一个您想要的键存在,而其他任何键都不存在。如果你return 0在那种情况下,它们将在你的数组中的其他键中被破坏(因为它们在这种情况下的位置被认为是相等的)。
由于您还希望保留现有键的序列,并在之后插入其他“提取的”键country_id,因此您可以保留对原始排序顺序的引用,并使用它来解析与country_id其他字段相关的排序顺序(和其他字段之间以保持当前排序顺序)
通过处理这两种特殊情况以明确地对您希望自己依次出现的键进行排序,您将获得满足您要求的结果:
$order = ['country_id' => 1, 'region' => 2, 'region_id' => 3, 'city' => 4, 'city_id' => 5];
$preset_order = array_flip(array_keys($array));
uksort($array, function ($a, $b) use ($order, $preset_order) {
if (isset($order[$a]) && isset($order[$b])) {
return $order[$a] - $order[$b];
} else if (isset($order[$a])) {
return $preset_order['country_id'] - $preset_order[$b];
} else if (isset($order[$b])) {
return $preset_order[$a] - $preset_order['country_id'];
} else {
return $preset_order[$a] - $preset_order[$b];
}
});
输出:
array(8) {
'name' =>
array(1) {
'value' =>
string(6) "Raj KB"
}
'street' =>
array(1) {
'value' =>
string(10) "Street ABC"
}
'country_id' =>
array(1) {
'value' =>
string(3) "UAE"
}
'region' =>
array(1) {
'value' =>
string(3) "DXB"
}
'region_id' =>
array(1) {
'value' =>
int(11)
}
'city' =>
array(1) {
'value' =>
string(5) "Dubai"
}
'city_id' =>
array(1) {
'value' =>
int(22)
}
'zip_code' =>
array(1) {
'value' =>
int(12345)
}
}
TA贡献1862条经验 获得超6个赞
PHP 使用Quicksort,因此您不能只为要排序的元素返回有意义的值。在我看来,在这里使用 uksort 是个坏主意,因为您必须使用数组的当前索引作为值,但这是不可能的,因为您无法从比较函数内部访问旧数组的副本。您还需要知道第一个特殊值在哪个索引上。
所以我建议这样做,因为我认为用 uksort 做你想做的事是不可能的:
function customSort($array)
{
$order = ['country_id' => 0, 'region' => 1, 'region_id' => 2, 'city' => 3, 'city_id' => 4];
$keyArray = array();
$sortedArray = array();
foreach ($array as $i => $value) {
$keyArray[] = $i;
}
$counter = 0;
$hasStarted = false;
$insertLater = array();
for ($i = 0; $i < count($keyArray); $i++) {
if ($hasStarted) {
if ($counter < count($order)) {
$sortedArray[array_search($counter, $order)] = $array[array_search($counter, $order)];
$counter++;
if (!isset($order[$keyArray[$i]])) {
array_push($insertLater, ["key" => $keyArray[$i], "value" => $array[$keyArray[$i]]]);
}
continue;
}
}
if (count($insertLater) > 0) {
$itemToInsert = array_shift($insertLater);
$sortedArray[$itemToInsert["key"]] = $itemToInsert["value"];
if (!isset($order[$keyArray[$i]])) {
array_push($insertLater, ["key" => $keyArray[$i], "value" => $array[$keyArray[$i]]]);
}
continue;
}
if (isset($order[$keyArray[$i]]) && !$hasStarted) {
$sortedArray[array_search($counter, $order)] = $array[array_search($counter, $order)];
$hasStarted = true;
$counter++;
continue;
}
$sortedArray[$keyArray[$i]] = $array[$keyArray[$i]];
}
return $sortedArray;
}
It's may
不是最好的解决方案,但它有效 O(n)。
- 3 回答
- 0 关注
- 145 浏览
添加回答
举报