如何对类似于链表的条目进行排序?
Posted
技术标签:
【中文标题】如何对类似于链表的条目进行排序?【英文标题】:how to sort entries similar to a linked list? 【发布时间】:2016-10-26 21:24:46 【问题描述】:我有以下数据结构,我想根据 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 做到这一点的巧妙方法?
【问题讨论】:
函数 usort() - php.net/manual/en/function.usort.php @splash58 不! ***.com/q/38008964/476 您能否更准确地描述您希望它如何排序?是否与以下内容有关:'after:9' 意味着所有 ID 低于 9 的条目之后,'before : 10' 意味着所有高于 10 的值都应该在这个之后? @rbaker86 写入结果中的 id 顺序 谢谢。我希望这些键的顺序是 0、4、1、2、3。我意识到 1 和 4 都指定“之后:14”,对于这种情况,优先级并不重要。 【参考方案1】:我认为没有直接的“单线”类型解决方案。
我不清楚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
*/
【讨论】:
【参考方案2】:我认为您可以使用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
【讨论】:
以上是关于如何对类似于链表的条目进行排序?的主要内容,如果未能解决你的问题,请参考以下文章