Php 如何按多个键、字符串和整数的值对多维数组排序

Php 如何按多个键、字符串和整数的值对多维数组排序,php,arrays,sorting,multidimensional-array,Php,Arrays,Sorting,Multidimensional Array,我有很多人(立法者)列出了他们的级别、州、商会和地区。我想要的是根据这4个键的值对数组进行排序,但是要使用自定义顺序,因为其中一些值是字符串。例如,我想先按“级别”排序,顺序是(“联邦”、“州”,然后是其他任何东西),然后按字母顺序升序排列州,然后按“州长”、“上级”、“下级”,然后是其他任何东西”,然后按数字顺序升序排列地区。下面是我正在使用的数组的一个简短示例 Array ( [0] => stdClass Object ( [district] => 1

我有很多人(立法者)列出了他们的级别、州、商会和地区。我想要的是根据这4个键的值对数组进行排序,但是要使用自定义顺序,因为其中一些值是字符串。例如,我想先按“级别”排序,顺序是(“联邦”、“州”,然后是其他任何东西),然后按字母顺序升序排列州,然后按“州长”、“上级”、“下级”,然后是其他任何东西”,然后按数字顺序升序排列地区。下面是我正在使用的数组的一个简短示例

Array
(
[0] => stdClass Object
    (
        [district] => 15
        [state] => fl
        [level] => state
        [chamber] => upper

    )

[1] => stdClass Object
    (
        [district] => 50
        [state] => fl
        [level] => state
        [chamber] => lower
    )
[2] => stdClass Object
    (
        [district] => 0
        [state] => fl
        [level] => state
        [chamber] => governor

    )
)
如果可以解决您的问题,您只需编写一个良好的比较函数即可按需要工作

<?php

$lawmakers = ... // Your lawmakers array.
usort($lawmakers, "cmp");

// returns 0 if equal; -1 if $a < $b; 1 otherwise
function cmp($a, $b) {
    // 1. Compare level: "federal" < "state" < anything else
    if ($a["level"] === "federal" && $b["level"] !== "federal") return -1;
    else if ($a["level"] !== "federal" && $b["level"] === "federal") return 1;
    else if ($a["level"] === "state" && $b["level"] !== "state") return -1;
    else if ($a["level"] !== "state" && $b["level"] === "state") return 1;
    // 2. Compare state: alphabetical order
    if (strcmp($a["state"], $b["state"]) > 0) return 1;
    else if (strcmp($a["state"], $b["state"]) < 0) return -1;
    // 3. Compare chamber: "governor" < "upper" < "lower" < anything else
    if ($a["chamber"] === "governor" && $b["chamber"] !== "governor") return -1;
    else if ($a["chamber"] !== "governor" && $b["chamber"] === "governor") return 1;
    else if ($a["chamber"] === "upper" && $b["chamber"] !== "upper") return -1;
    else if ($a["chamber"] !== "upper" && $b["chamber"] === "upper") return 1;
    else if ($a["chamber"] === "lower" && $b["chamber"] !== "lower") return -1;
    else if ($a["chamber"] !== "lower" && $b["chamber"] === "lower") return 1;
    // 4. Compare district: ascending
    if ($a["district"] < $b["district"]) return -1;
    else if ($a["district"] > $b["district"]) return 1;
    // 5. If we came so far... $a and $b are equals
    return 0;
}
?>

您还可以考虑一个面向对象的解决方案(它仍然需要一个比较函数…)


@BusyBeaver的解决方案
cmp()
/
compare()
函数非常复杂,如果您想更改顺序或添加其他字段,则很难更新

这就是我想到的:

<?php
function sortValue($key, $value)
{
    static $arrValueOrder = [
        'level' => ['federal', 'state'],
        'chamber' => ['governor', 'upper', 'lower']
    ];

    if (array_key_exists($key, $arrValueOrder)) {
        if (($result = array_search($value, $arrValueOrder[$key])) === false) {
            $result = count($arrValueOrder[$key]);
        }
    } else {
        $result = $value;
    }
    return $result;
}

function cmp($a, $b)
{
    static $arrFieldOrder = ['level', 'state', 'chamber', 'district'];

    $result = 0;
    reset($arrFieldOrder);
    while ($result === 0 && list($key, $value) = each($arrFieldOrder)) {
        $aSortValue = sortValue($value, $a->$value);
        $bSortValue = sortValue($value, $b->$value);
        if ($aSortValue > $bSortValue) {
            $result = 1;
        } elseif ($aSortValue < $bSortValue) {
            $result = -1;
        }
    }
    return $result;
}

// setup some test data
$arrData = [
    (object)['district' => 15, 'state' => 'fl', 'level' => 'state', 'chamber' => 'upper'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'lower'],
    (object)['district' => 50, 'state' => 'fl', 'level' => 'state', 'chamber' => 'lower'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'upper'],
    (object)['district' => 0, 'state' => 'fl', 'level' => 'state', 'chamber' => 'governor'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'governor'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'foo'],
    (object)['district' => 15, 'state' => 'fl', 'level' => 'federal', 'chamber' => 'upper']
];

// sort it
usort($arrData, 'cmp');

// dump the result
var_dump($arrData);

你能提供一些你到目前为止尝试过的代码吗?@BusyBeaver-我从那时起就删除了这些代码,但与此类似<代码>函数cmp($a,$b){if($a==$b){return 0;}return($a<$b)?-1:1;}usort($a,“cmp”)嗯。。。这似乎一点帮助都没有。。。我认为最好的解决方案是创建由
地区
等定义的自己的对象;创建您自己的比较函数,该函数按您希望的方式工作,最后使用您喜欢的排序算法对数组进行排序;i、 e.,1。对整个数组进行排序,比较最重要的键(级别),;2.按状态对具有相同级别的子数组进行排序;3.按腔室对具有相同级别和状态的子阵列进行排序。。。等等丑陋的解决方案,但仍然…谢谢你的帮助,但这可能超出了我目前的知识(有点新手),所以我可能不得不尝试外包。惊人的解决方案!非常感谢!绝对是一种不那么复杂的方式。特别是像你说的,在未来增加不同的领域,这是一个巨大的可能性。非常感谢。
<?php
function sortValue($key, $value)
{
    static $arrValueOrder = [
        'level' => ['federal', 'state'],
        'chamber' => ['governor', 'upper', 'lower']
    ];

    if (array_key_exists($key, $arrValueOrder)) {
        if (($result = array_search($value, $arrValueOrder[$key])) === false) {
            $result = count($arrValueOrder[$key]);
        }
    } else {
        $result = $value;
    }
    return $result;
}

function cmp($a, $b)
{
    static $arrFieldOrder = ['level', 'state', 'chamber', 'district'];

    $result = 0;
    reset($arrFieldOrder);
    while ($result === 0 && list($key, $value) = each($arrFieldOrder)) {
        $aSortValue = sortValue($value, $a->$value);
        $bSortValue = sortValue($value, $b->$value);
        if ($aSortValue > $bSortValue) {
            $result = 1;
        } elseif ($aSortValue < $bSortValue) {
            $result = -1;
        }
    }
    return $result;
}

// setup some test data
$arrData = [
    (object)['district' => 15, 'state' => 'fl', 'level' => 'state', 'chamber' => 'upper'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'lower'],
    (object)['district' => 50, 'state' => 'fl', 'level' => 'state', 'chamber' => 'lower'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'upper'],
    (object)['district' => 0, 'state' => 'fl', 'level' => 'state', 'chamber' => 'governor'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'governor'],
    (object)['district' => 15, 'state' => 'tx', 'level' => 'federal', 'chamber' => 'foo'],
    (object)['district' => 15, 'state' => 'fl', 'level' => 'federal', 'chamber' => 'upper']
];

// sort it
usort($arrData, 'cmp');

// dump the result
var_dump($arrData);