我从数据库数组中得到了这样的结果(用户选择按价格排序):
Array
(
[0] => Array
(
[id] => 812
[price] => 0
[par_id] => 310
)
[1] => Array
(
[id] => 445
[price] => 3400
[par_id] => 0
)
[2] => Array
(
[id] => 1102
[price] => 3500
[par_id] => 0
)
[3] => Array
(
[id] => 310
[price] => 3700
[par_id] => 0
)
[4] => Array
(
[id] => 311
[price] => 3700
[par_id] => 310
)
[5] => Array
(
[id] => 800
[price] => 3900
[par_id] => 310
)
)
我需要将此数组排序为par_id==0的项,在它们下面是它的子项child.par_id=parent.id。要获得带有这些contidion的数组,我使用函数usort():
usort($array,"cmp");
function cmp($a, $b) {
if ( $a['id'] == $b['id'] ) {
return 0;
} else if ( $a['par_id'] ) {
if ( $a['par_id'] == $b['par_id'] ) {
return ( $a['id'] < $b['id'] ? -1 : 1 );
} else {
return ( $a['par_id'] >= $b['id'] ? 1 : -1 );
}
} else if ( $b['par_id'] ) {
return ( $b['par_id'] >= $a['id'] ? -1 : 1);
} else {
return ( $a['id'] < $b['id'] ? -1 : 1 );
}
}
它工作,然后我得到这样的数组:
Array
(
[0] => Array
(
[id] => 310
[price] => 3700
[par_id] => 0
)
[1] => Array
(
[id] => 311
[price] => 3700
[par_id] => 310
)
[2] => Array
(
[id] => 800
[price] => 3900
[par_id] => 310
)
[3] => Array
(
[id] => 812
[price] => 0
[par_id] => 310
)
[4] => Array
(
[id] => 445
[price] => 3400
[par_id] => 0
)
[5] => Array
(
[id] => 1102
[price] => 3500
[par_id] => 0
)
)
但是,这个数组不是按价格排序的。我的问题是,如果可以在上述状态下对数组进行排序,但也可以保持按价格排序,至少在父级(在子级也是理想情况)。所以我想要得到的结果数组是这样的:
Array
(
[0] => Array
(
[id] => 445
[price] => 3400
[par_id] => 0
)
[1] => Array
(
[id] => 1102
[price] => 3500
[par_id] => 0
)
[2] => Array
(
[id] => 310
[price] => 3700
[par_id] => 0
)
[3] => Array
(
[id] => 812
[price] => 0
[par_id] => 310
)
[4] => Array
(
[id] => 311
[price] => 3700
[par_id] => 310
)
[5] => Array
(
[id] => 800
[price] => 3900
[par_id] => 310
)
)
父级优先,紧随其后的是其子级AND,仍然按用户选择的价格排序。
好问题。您不会在cmp
函数中比较价格,因此生成的列表不按价格排序是合乎逻辑的。查看以下cmp
函数:
function cmp($a, $b) {
if ($a['id'] === $b['id']) {
return 0;
}
// both are child or both are parents, so compare by price
$comparePrices = ($a['par_id'] && $b['par_id'])
|| (!$a['par_id'] && !$b['par_id']);
$priceResult = $a['price'] > $b['price'] ? 1 : -1;
if ($comparePrices) {
return $priceResult;
} else if ($a['par_id']) {
// a is a child, so check if b is the parent
return $a['par_id'] === $b['id'] ? 1 : $priceResult;
} else if ($b['par_id']) {
// b is a child, so check if a is the parent
return $b['par_id'] === $a['id'] ? -1 : $priceResult;
}
}
这应该有效,但不能保证它适用于所有情况。
出于可读性的考虑,您无论如何都应该实现这种不同的方式。将您的查询一分为二。第一个按价格获取所有父项和订单,第二个按父项id然后按价格获取全部子项和订单。这些数组的合并操作是foreach
和array_map
的简单组合。例如:
$childItemsByParentId = [];
foreach ($childItems as $childItem) {
$childItemsByParentId[$childItem['par_id']][] = $childItem;
}
$parentItems = array_map(function ($parentItem) use ($childItemsByParentId) {
$childs = isset($childItemsByParentId[$parentItem['id']])
? $childItemsByParentId[$parentItem['id']]
: [];
$parentItem['childs'] = $childs;
return $parentItem;
}, $parentItems);
我最终发明了另一种方法。
它遍历整个数组,找出实际项是父项还是子项。如果它是子对象,它将再次遍历数组以找到其父对象。如果找到了父项,它会向前或向后移动子项和父项位置之间的所有项(取决于子项在哪里——是在父项的前面还是后面),以在数组中形成一个空间,子项将放置在哪里。
$last_id = 0;
for($i = 0; $i < count($data); $i++) {
$item = $data[$i];
if ($item['par_id'] == 0) {
$last_id = $item['id'];
continue;
}
if ($last_id == $item['par_id']) {
continue;
}
foreach($data as $d => $dat) {
if ($item['par_id'] == $dat['id']) {
if ($i < $d) {
for($j = $i; $j < $d; $j++) { $data[$j] = $data[$j + 1]; }
$empty = $d;
$i -= 1;
} else {
for($j = $i; $j > $d; $j--) { $data[$j] = $data[$j - 1]; }
$empty = $d + 1;
}
$data = $item;
} } }