排序数组 - 其父项后的子项,但保持父项彼此的位置

时间:2013-11-21 01:06:30

标签: php arrays sorting

我从这样的数据库数组中获取(用户选择按价格排序):

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 。要使用这些contidions获取数组,我使用函数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
        )
)

父母首先,紧接着他们的孩子并且仍按用户选择的价格排序。

2 个答案:

答案 0 :(得分:1)

好问题。您没有比较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然后按价格提取所有孩子和订单。这些数组的合并操作是foreacharray_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);

答案 1 :(得分:0)

我发明了另一种方法,最终如何做到这一点。

它遍历整个数组并查明实际项目是父项还是子项。如果是孩子,它会再次通过数组来查找其父级。如果父项被查找,它会向前或向后移动子项和父项之间的所有项(取决于子项的位置 - 如果在父项之前或之后)在数组中创建一个空格,将放置子项。

$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;
    } } }