使用多个条件在PHP中对多维数组进行排序

时间:2016-12-12 11:09:21

标签: php arrays sorting multidimensional-array

我试图从数据库查询中构建一个结果数组,基本上我想知道以下是否可能

数组内容:

Array
(
    [0] => Array
        (
            [Section_Id] => 1
            [Section_Name] => "Section1"
            [Section_Parent] => NULL
            [Section_Position] => 0
            [Section_Depth] => 0
        )

    [1] => Array
        (
            [Section_Id] => 3
            [Section_Name] => "Section2"
            [Section_Parent] => NULL
            [Section_Position] => 1
            [Section_Depth] => 0

        )

    [2] => Array
        (
            [Section_Id] => 4
            [Section_Name] => "SubSection1ForSection2"
            [Section_Parent] => 3
            [Section_Position] => 0
            [Section_Depth] => 1
        )

    [3] => Array
        (
            [Section_Id] => 2
            [Section_Name] => "SubSection1ForSection1"
            [Section_Parent] => 1
            [Section_Position] => 0
            [Section_Depth] => 1
        )

)

如果您要对此进行排序,请在Section_Position上说它会返回如下内容:

usort($sections, function($a, $b) {
     return $a['section_position'] - $b['section_position'];
});
  1. SECTION1
  2. SubSection1ForSection2
  3. SubSection1ForSection1
  4. 第2节
  5. 虽然我需要它与各自的孩子一起订购章节:

    1. SECTION1
    2. SubSection1ForSection1
    3. 第2节
    4. SubSection1ForSection2
    5. 我认为Somehow Duplicate Question是思考的方式,但我似乎无法找到让我这样做的方法。

      有没有办法做到这一点,或者我必须使用forloop-gets进行解决方法,以便我首先获取深度为1的所有值,然后使用该部分的名称来获取深度为2的所有值那么?

      (抱歉我的英文。)

1 个答案:

答案 0 :(得分:1)

好吧这可能是一个丑陋的解决方案,但如果你把所有东西放在一个函数中它看起来不错:)。好处是它可以在您的场景中运行。

代码:

$inputData = array(
    array(
        'Section_Id' => 1,
        'Section_Name' => "Section1",
        'Section_Parent' => NULL,
        'Section_Position' => 1,
        'Section_Depth' => 0,
    ),
    array(
        'Section_Id' => 2,
        'Section_Name' => "Section2",
        'Section_Parent' => NULL,
        'Section_Position' => 0,
        'Section_Depth' => 0
    ),
    array(
        'Section_Id' => 4,
        'Section_Name' => "SubSection2ForSection2",
        'Section_Parent' => 2,
        'Section_Position' => 1,
        'Section_Depth' => 1
    ),
    array(
        'Section_Id' => 5,
        'Section_Name' => "SubSection1ForSection2",
        'Section_Parent' => 2,
        'Section_Position' => 0,
        'Section_Depth' => 1
    ),
    array(
        'Section_Id' => 3,
        'Section_Name' => "SubSection1ForSection1",
        'Section_Parent' => 1,
        'Section_Position' => 0,
        'Section_Depth' => 1
    )
);


$parentRecords = array();
$childRecords = array();
$sorted = array();

/* split in two collections */
foreach ($inputData as $sectionData) {
    if (is_null($sectionData['Section_Parent'])) {
        /* assume this is a parent */
        $parentRecords[] = $sectionData;
    } else {
        /* assume we are on child row */
        $childRecords[] = $sectionData;
    }
}

/* now first order parents by Section_Position */
usort($parentRecords, function($a, $b) {

        if ($a['Section_Position'] == $b['Section_Position']) {
            return 0;
        }
        return $a['Section_Position'] > $b['Section_Position'] ? 1 : -1;
    });

/* now the actual sorting */
foreach ($parentRecords as $parentData) {
    $parentId = $parentData['Section_Id'];
    /* now get all children of this parent */
    $parentChildren = array();
    foreach ($childRecords as $childData) {
        if ($childData['Section_Parent'] == $parentId) {
            $parentChildren[] = $childData;
        }
    }

    /* now sort the children by Section_Position */
    usort($parentChildren, function($a, $b) {

        if ($a['Section_Position'] == $b['Section_Position']) {
            return 0;
        }
        return $a['Section_Position'] > $b['Section_Position'] ? 1 : -1;
    });

    $sorted[] = $parentData;
    $sorted = array_merge($sorted, $parentChildren);
}


echo '<pre>' . print_r($sorted, true) . '</pre>';
exit;

输出:

Array
(
    [0] => Array
        (
            [Section_Id] => 2
            [Section_Name] => Section2
            [Section_Parent] => 
            [Section_Position] => 0
            [Section_Depth] => 0
        )

    [1] => Array
        (
            [Section_Id] => 5
            [Section_Name] => SubSection1ForSection2
            [Section_Parent] => 2
            [Section_Position] => 0
            [Section_Depth] => 1
        )

    [2] => Array
        (
            [Section_Id] => 4
            [Section_Name] => SubSection2ForSection2
            [Section_Parent] => 2
            [Section_Position] => 1
            [Section_Depth] => 1
        )

    [3] => Array
        (
            [Section_Id] => 1
            [Section_Name] => Section1
            [Section_Parent] => 
            [Section_Position] => 1
            [Section_Depth] => 0
        )

    [4] => Array
        (
            [Section_Id] => 3
            [Section_Name] => SubSection1ForSection1
            [Section_Parent] => 1
            [Section_Position] => 0
            [Section_Depth] => 1
        )

)

注意:第一次排序是针对父母的Section_Position,然后是孩子的Section_Position

U P D A T E

首先,我想对主持人与@Akorna进行长时间的讨论表示遗憾,但我需要向他提供这些代码,我认为它将为未来做好准备。所以@Akorna应该适合你的代码就是这个:

$inputData = array(
    array(
        'section_id' => 333,
        'section_depth' => 1,
        'section_parent' => 332,
        'section_position' => 0,
        'section_title' => 'Introduction'),
    array(
        'section_id' => 334,
        'section_depth' => 1,
        'section_parent' => 332,
        'section_position' => 1,
        'section_title' => 'Glossary'),
    array(
        'section_id' => 335,
        'section_depth' => 1,
        'section_parent' => 332,
        'section_position' => 2,
        'section_title' => 'Commands'),
    array(
        'section_id' => 336,
        'section_depth' => 1,
        'section_parent' => 332,
        'section_position' => 3,
        'section_title' => 'Components'),
    array(
        'section_id' => 337,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 0,
        'section_title' => 'Introduction'),
    array(
        'section_id' => 407,
        'section_depth' => 2,
        'section_parent' => 401,
        'section_position' => 2,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 338,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 1,
        'section_title' => 'AbstractContainer'),
    array(
        'section_id' => 406,
        'section_depth' => 2,
        'section_parent' => 401,
        'section_position' => 1,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 339,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 2,
        'section_title' => 'ActionsContainer'),
    array(
        'section_id' => 340,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 3,
        'section_title' => 'BrowserIncompatibility'),
    array(
        'section_id' => 404,
        'section_depth' => 2,
        'section_parent' => 402,
        'section_position' => 3,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 341,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 4,
        'section_title' => 'CollapsibleContainer'),
    array(
        'section_id' => 342,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 5,
        'section_title' => 'DetailsContainer'),
    array(
        'section_id' => 343,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 6,
        'section_title' => 'DynamicMenu'),
    array(
        'section_id' => 403,
        'section_depth' => 2,
        'section_parent' => 402,
        'section_position' => 1,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 344,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 7,
        'section_title' => 'Settings'),
    array(
        'section_id' => 345,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 8,
        'section_title' => 'SubfilesViewer'),
    array(
        'section_id' => 346,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 9,
        'section_title' => 'Taxonomy Management'),
    array(
        'section_id' => 402,
        'section_depth' => 1,
        'section_parent' => 400,
        'section_position' => 2,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 401,
        'section_depth' => 1,
        'section_parent' => 400,
        'section_position' => 1,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 347,
        'section_depth' => 2,
        'section_parent' => 336,
        'section_position' => 10,
        'section_title' => 'UploadQueue'),
    array(
        'section_id' => 400,
        'section_depth' => 0,
        'section_parent' => null,
        'section_position' => 5,
        'section_title' => 'Web Application'),
    array(
        'section_id' => 332,
        'section_depth' => 0,
        'section_parent' => null,
        'section_position' => 3,
        'section_title' => 'Web Application')
);

/* first order by section_depth and then by section_position */
$inputData = array_orderby($inputData, 'section_depth', SORT_ASC, 'section_position', SORT_ASC);

$parents = array();
$sortedByParent = false;
while (!$sortedByParent) {
    $elems = array_splice($inputData, count($inputData) - 1, 1);
    if (!count($elems)) {
        $sortedByParent = true;
        $inputData = array_merge($inputData, $parents);
        continue;
    }

    $elem = $elems[0];

    if ($elem['section_depth'] == 0) {
        if (!isset($elem['children'])) {
            $elem['children'] = array();
        }
        $parents[] = $elem;
    } else {
        $inputData = put_in_parent($elem, $inputData);
    }
}

/* now we have $inputData in nice format like
 * parent(child, child, child(child, child(child, child)), child(child(child(child)))),
 * parent(child, child, child(child, child(child, child)), child(child(child(child))))
 *  */
$inputData = merge_children_recursively(array_reverse($inputData));

function merge_children_recursively($inputData) {
    $children = array();
    foreach ($inputData as $row) {
        if (isset($row['children'])) {
            /* this ksort call is necessary because the key is actually section_position */
            ksort($row['children']);
            $rowCopy = $row;
            unset($rowCopy['children']);
            $children[] = $rowCopy;
            $children = array_merge($children, merge_children_recursively($row['children']));
        } else {
            $children[] = $row;
        }
    }

    return $children;
}

function put_in_parent($elem, $inputData) {
    foreach ($inputData as $k => $row) {
        if ($row['section_id'] == $elem['section_parent']) {
            if (!isset($inputData[$k]['children'])) {
                $inputData[$k]['children'] = array();
            }

            $inputData[$k]['children'][$elem['section_position']] = $elem;
            break;
        }
    }
    return $inputData;
}

function array_orderby() {
    $args = func_get_args();
    $data = array_shift($args);
    foreach ($args as $n => $field) {
        if (is_string($field)) {
            $tmp = array();
            foreach ($data as $key => $row) {
                $tmp[$key] = $row[$field];
            }
            $args[$n] = $tmp;
        }
    }
    $args[] = &$data;
    call_user_func_array('array_multisort', $args);
    return array_pop($args);
}

echo '<pre>' . print_r($inputData, true) . '</pre>';
exit;

我确实从输入数据中删除了一些东西,所以我可以自己定位。只是尝试将输入数据提供给逻辑,让我知道结果是什么。