我有以下数据结构,我想根据before
和after
值对此进行排序。
array (size=5)
0 =>
array (size=3)
'id' => int 14
'parentId' => int 0
'before' => int 15
1 =>
array (size=3)
'id' => int 15
'parentId' => int 0
'after' => int 14
2 =>
array (size=3)
'id' => int 9
'parentId' => int 0
'after' => int 15
3 =>
array (size=3)
'id' => int 8
'parentId' => int 0
'after' => int 9
4 =>
array (size=3)
'id' => int 1
'parentId' => int 0
'after' => int 14
有没有巧妙的方法用PHP做到这一点?
答案 0 :(得分:0)
我认为这不是一个直截了当的"单线"解决这个问题。
我不清楚parentId
是否对排序有任何意义,但如果没有,这与我本周早些时候回答的this question about sorting an array of Javascript includes by dependency非常相似。
唯一真正的区别在于,在依靠依赖性排序之前,您需要在"之前转换那些"进入"""相应行上的条目。
$data = [
["id" => 14, "parentId" => 0, "before" => 15],
["id" => 15, "parentId" => 0, "after" => 14],
["id" => 9, "parentId" => 0, "after" => 15],
["id" => 8, "parentId" => 0, "after" => 9],
["id" => 1, "parentId" => 0, "after" => 14]
];
// Use the ID of each element as the array index.
$data = array_combine(array_column($data, "id"), $data);
// Convert each "after" entry into an array.
$data = array_map(function($element) {
$element["after"] = isset($element["after"]) ? [$element["after"]] : [];
return $element;
}, $data);
// Convert each "before" entry into an "after" entry.
foreach ($data as $id => $element) {
if (isset($element["before"])) {
$data[$element["before"]]["after"][] = $id;
unset($data[$id]["before"]);
}
}
// Remove empty "after" entries.
$data = array_map(function($element) {
if (!count($element["after"])) {
unset($element["after"]);
}
return $element;
}, $data);
$sorted = [];
while ($count = count($data)) {
// Remove any met dependencies.
foreach ($data as $id => $element) {
if (isset($element["after"])) {
foreach ($element["after"] as $after_id => $after_element) {
if (isset($sorted[$after_element])) {
unset($data[$id]["after"][$after_id]);
}
}
if (!count($data[$id]["after"])) {
unset($data[$id]["after"]);
}
}
}
// Add elements with no more dependencies to the output array.
foreach ($data as $id => $element) {
if (!isset($element["after"])) {
$sorted[$id] = $element;
unset($data[$id]);
}
}
if (count($data) == $count) {
die("Unresolvable dependency");
}
}
var_dump($sorted);
/*
array (size=5)
14 =>
array (size=2)
'id' => int 14
'parentId' => int 0
15 =>
array (size=2)
'id' => int 15
'parentId' => int 0
1 =>
array (size=2)
'id' => int 1
'parentId' => int 0
9 =>
array (size=2)
'id' => int 9
'parentId' => int 0
8 =>
array (size=2)
'id' => int 8
'parentId' => int 0
*/
答案 1 :(得分:0)
我认为您可以根据自己的需要使用uasort()
功能。
要定义比较函数,我建议将所有after
条件转换为before
条件:
$array = [
[
'id' => 14,
'parentId' => 0,
'before' => 15
],
[
'id' => 15,
'parentId' => 0,
'after' => 14
],
[
'id' => 9,
'parentId' => 0,
'after' => 15
],
[
'id' => 8,
'parentId' => 0,
'after' => 9
],
[
'id' => 1,
'parentId' => 0,
'after' => 14
]
];
//transform all after conditions to before conditions
function defineBeforeCondition($array)
{
$befores = array_column($array, 'before', 'id');
$afters = array_column($array, 'after', 'id');
return array_merge(array_chunk($befores, 1, true), array_map('array_flip', array_chunk($afters, 1, true)));
}
$condition = defineBeforeCondition($array);
现在您可以在比较函数中使用$condition
:
$compare = function ($array1, $array2) use ($condition)
{
//iterate through before conditions
foreach ($condition as $before) {
//if there is a match
if (isset($before[$array1['id']]) && $before[$array1['id']] === $array2['id']) {
//if the value of the first element is greater than the value of the second element,
//but the first element should precede the second, return -1
if ($array1['id'] > $array2['id']) {
return -1;
}
//otherwise make a normal comparison
//note the spaceship operator for PHP >= 7.0
return $array1['id'] <=> $array2['id'];
}
}
//no data, move down the first element
return 1;
};
uasort($array, $compare);
var_dump($array);
array (size=5)
0 =>
array (size=3)
'id' => int 14
'parentId' => int 0
'before' => int 15
4 =>
array (size=3)
'id' => int 1
'parentId' => int 0
'after' => int 14
1 =>
array (size=3)
'id' => int 15
'parentId' => int 0
'after' => int 14
2 =>
array (size=3)
'id' => int 9
'parentId' => int 0
'after' => int 15
3 =>
array (size=3)
'id' => int 8
'parentId' => int 0
'after' => int 9