代码之家  ›  专栏  ›  技术社区  ›  Danny Valariola

按预定义的值映射对对象数组进行排序

  •  1
  • Danny Valariola  · 技术社区  · 6 年前

    我有以下数组:

    $inputArray = Array(
        [0] => stdClass Object (
            [id] => 8
        )
    
        [1] => stdClass Object (
            [id] => 7
        )
    
        [2] => stdClass Object (
            [id] => 5
        )
    )
    
    $sortingArray = [5,8,1]
    

    我正在寻找一种按id“值映射”对输入数组排序的有效方法。。预期的输出应该是$inputArray重新排序,这样第三项将是第一项,第一项将是第二项等。

    3 回复  |  直到 6 年前
        1
  •  1
  •   Nigel Ren    6 年前

    array_replace() 我用 array_column() 索引对象(这需要PHP7.0+来处理对象)。。。

    $input = array_column($inputArray, null, "id");   
    $sort = array_fill_keys($sortingArray, null);
    $output = array_filter(array_replace($sort, $input));
    

    这个 array_filter() 将删除不在输入数组中但在排序数组中的任何元素。这个 array_fill_keys() array_flip() 所以我可以设置一个空值,允许过滤器工作。

        2
  •  2
  •   Eddie    6 年前

    你可以用 array_flip 制作临时数组。这将翻转数组意味着值将是键。

    使用 usort

    $tempArr = array_flip( $sortingArray  );
    usort($inputArray, function($a, $b) use ( $tempArr ) {
        $tempA = isset( $tempArr[ $a->id ] ) ? $tempArr[ $a->id ] : 999999; //If id does not exist on $sortingArray. Use 999999 as an index
        $tempB = isset( $tempArr[ $b->id ] ) ? $tempArr[ $b->id ] : 999999;
        return $tempA - $tempB;
    });
    
    echo "<pre>";
    print_r( $inputArray );
    echo "</pre>";
    

    这将导致:

    Array
    (
        [0] => stdClass Object
            (
                [id] => 5
            )
    
        [1] => stdClass Object
            (
                [id] => 8
            )
    
        [2] => stdClass Object
            (
                [id] => 7
            )
    
    )
    
        3
  •  0
  •   mickmackusa    6 年前

    首先,如果您的输入数组是MySQL查询的结果集,那么您应该通过orderby子句对数据进行排序。 FIELD() 是一个很好的工具,有点奇怪,你需要颠倒你的排序逻辑和写 DESC 在函数之后。

    资源: https://www.electrictoolbox.com/mysql-order-specific-field-values/

    SQL Fiddle演示: http://sqlfiddle.com/#!9/6b996f/1


    除此之外,我将提供Nigel和Eddie的解决方案的两个精炼版本,利用php7+的优点。您选择实施哪一项与以下内容有关:

    1. 是否允许具有重复项的元素 id
    2. 哪一个对你的工作效率更高 实际的 项目数据(输入数组和自定义订单数组的大小)

    解决方案1: usort() null coalescing operator

    PHP Demo

    $array = [
        (object)['id' => 8],
        (object)['id' => 7],
        (object)['id' => 5]
    ];
    
    $order = [5, 8, 1];  // custom sort order
    
    $order = array_flip($order);  // restructure for easy lookup with isset()
    $order[''] = max(array_column($array, 'id')) + 1;  // append value higher than max for outlying ids
    
    usort($array, function($a, $b) use ($order) {
        return ($order[$a->id] ?? $order['']) <=> ($order[$b->id] ?? $order['']);
    });
    var_export($array);
    

    *注意我本来可以通过的 $outlier use 并替换了所有 $order[''] 变量 $异常值 ,但我选择将异常数据附加到查找数组中。

    *我在自定义函数中使用括号不仅是为了提高可读性,而且是为了保证计算按预期执行——实际上,我没有费心去检查没有括号分组的计算是否相同。

    解决方案2: array_replace() 翻页的&带键控数组的过滤排序数组

    ( PHP Demo )

    $array = [
        (object)['id' => 8],
        (object)['id' => 7],
        (object)['id' => 5]
    ];
    
    $order = [5, 8, 1];
    
    $order = array_flip($order);                            // flip for future key comparisons
    $keyed = array_column($array, null, 'id');              // declare id values as new keys
    $filtered_order = array_intersect_key($order, $keyed);  // remove unwanted order keys
    $replaced = array_replace($filtered_order, $keyed);     // apply objects to output array
    var_export(array_values($replaced));                    // re-index the output (if desired)
    

    null 值,它不会删除“错误”的值。

    *我将再次声明 array_column() 如果有重复数据会损坏数据 身份证件 输入数组中的值。