按从相邻值中选择的深度嵌套属性对对象数组排序


Sort an array of objects by deeply nested property selected from an adjacent value

我正在调用一个REST API,它返回一个对象数组。其中一些包含内部有对象的进一步数组,如:

Array
(
    [0] => stdClass Object
        (
            [OPPORTUNITY_ID] => 7443729
            [CUSTOMFIELDS] => Array
                (
                    [0] => stdClass Object
                        (
                            [CUSTOM_FIELD_ID] => OPPORTUNITY_FIELD_7
                            [FIELD_VALUE] => Zorem
                        )
                    [1] => stdClass Object
                        (
                            [CUSTOM_FIELD_ID] => OPPORTUNITY_FIELD_8
                            [FIELD_VALUE] => Zappem
                        )
                )
        )
    [1] => stdClass Object
        (
            [OPPORTUNITY_ID] => 7401996
            [CUSTOMFIELDS] => Array
                (
                    [0] => stdClass Object
                        (
                            [CUSTOM_FIELD_ID] => OPPORTUNITY_FIELD_7
                            [FIELD_VALUE] => Aorem
                        )
                    [1] => stdClass Object
                        (
                            [CUSTOM_FIELD_ID] => OPPORTUNITY_FIELD_8
                            [FIELD_VALUE] => Arappem
                        )
                )
        )
    // [etc.]
)

我想做的是根据OPPORTUNITY_IDCUSTOM_FIELD_ID/FIELD_VALUE对数组中的第一级对象进行排序。

作为一个场景,用户将点击链接:"Sort by OPPORTUNITY_FIELD_7",数组元素[1]将成为[0],因为"Aorem"具有比"Zorem"更高的字母值。

我已经设法使用usort对第一级对象进行排序:

function sort_results( $a, $b ) {
    if ($a->OPPORTUNITY_ID == $b->OPPORTUNITY_ID) return 0;
    else if ($a->OPPORTUNITY_ID > $b->OPPORTUNITY_ID) return -1;
    else return 1;
}
usort( $json_opportunities, "sort_results" );

但是我不知道如何从像OPPORTUNITY_FIELD_7这样的2级值排序的第一基础开始。有什么建议吗?我是否需要将所有内容都放入数组并以这种方式排序,或者是否有一种方法可以在不重写数组的情况下进行排序?

我们只需要一个更高级的usort()回调。例如,使用OPPORTUNITY_FIELD_7对数组排序将比较以下值:

  • $restArray[0]->CUSTOMFIELDS[0]->FIELD_VALUE
  • $restArray[1]->CUSTOMFIELDS[0]->FIELD_VALUE

因为OPPORTUNITY_FIELD_7与我们用来排序的值在同一个数组中,而不是它的索引,所以我们需要首先找到它所属的数字索引。这是通过循环CUSTOMFIELDS直到找到OPPORTUNITY_FIELD_7来完成的。

// callback for usort() using "OPPORTUNITY_FIELD_7"
function sort_OF7($a, $b) {
    // get the index where "OPPORTUNITY_FIELD_7" is stored
    foreach($a->CUSTOMFIELDS as $index => $arr) {
        if($arr->CUSTOM_FIELD_ID == 'OPPORTUNITY_FIELD_7') {
            $ai = $index;
            break;
        }
    }
    // again
    foreach($b->CUSTOMFIELDS as $index => $arr) {
        if($arr->CUSTOM_FIELD_ID == 'OPPORTUNITY_FIELD_7') {
            $bi = $index;
            break;
        }
    }
    // compare values
    return strcmp(
        $a->CUSTOMFIELDS[$ai]->FIELD_VALUE,
        $b->CUSTOMFIELDS[$bi]->FIELD_VALUE
    );
}

假设OPPORTUNITY_FIELD_7在对象中始终可用。

我们可以快速测试它:

// test
$main = JSON_decode('[{"OPPORTUNITY_ID":7443729,"CUSTOMFIELDS":[{"CUSTOM_FIELD_ID":"OPPORTUNITY_FIELD_7","FIELD_VALUE":"Zorem"},{"CUSTOM_FIELD_ID":"OPPORTUNITY_FIELD_8","FIELD_VALUE":"Zappem"}]},{"OPPORTUNITY_ID":7401996,"CUSTOMFIELDS":[{"CUSTOM_FIELD_ID":"OPPORTUNITY_FIELD_7","FIELD_VALUE":"Aorem"},{"CUSTOM_FIELD_ID":"OPPORTUNITY_FIELD_8","FIELD_VALUE":"Arappem"}]}]');
print_r($main);
usort($main, 'sort_OF7');
print_r($main);