简体   繁体   English

PHP 如何使用字母顺序备份基于优先级顺序对对象数组进行排序?

[英]PHP How to sort an array of objects based on priority order with a backup of alphabetical?

I have an array like this:我有一个这样的数组:

$sort_me = array(
   array("file"=>"Desert.jpg"), 
   array("file"=>"Hello.jpg"), 
   array("file"=>"Test.jpg)
)

I want to sort this array based on the file attribute alphabetically.我想根据文件属性按字母顺序对这个数组进行排序。 To complicate matters I have an optional array:为了使事情复杂化,我有一个可选数组:

$sort_order = array("Test.jpg", "Hello.jpg", "NotFound.jpg")

This array will specify some user defined ordering.该数组将指定一些用户定义的排序。 These array elements have priority, and will be placed in that order if they are found.这些数组元素具有优先级,如果找到它们将按该顺序放置。 Other elements not matching anything in $sort_order should be ordered at the end of the array alphabetically.$sort_order中的任何内容不匹配的其他元素应按字母顺序排列在数组的末尾。

In javascript I would use call a sort function with a comparator function that takes 2 elements and returns a number to place the first object ahead or behind the second. In javascript I would use call a sort function with a comparator function that takes 2 elements and returns a number to place the first object ahead or behind the second.

How can I do this with PHP?如何使用 PHP 做到这一点?

Edit编辑

I attempted something and it didn't work.我尝试了一些东西,但没有成功。 (Modified again to put the logic into one function, and generalize which field to sort by) (再次修改,将逻辑放到一个function中,并概括按哪个字段排序)

<?php
    function sort_priority($sort_me, $sort_order, $field) {
        function compare($a, $b) {
            if ($sort_order) {
                $ai = array_search($a[$field], $sort_order);
                $bi = array_search($b[$field], $sort_order);
                if ($ai !== false && $bi === false) {
                    return -1;
                } else if ($bi !== false && $ai === false) {
                    return 1;
                } else if ($ai !== false && $bi !== false) {
                    return $bi - $ai;
                }
            }
            return $a[$field] < $b[$field] ? -1 : 1;
        }
        usort($sort_me, "compare");
    }

    $sort_order = array("Test.jpg", "Hello.jpg", "NotFound.jpg");
    $sort_me = array(
       array("file"=>"Test.jpg"),
       array("file"=>"Desert.jpg"),
       array("file"=>"Hello.jpg")
    );

    sort_priority($sort_me, $sort_order, "file");
    echo json_encode($sort_me);
?>

This outputs这输出

 Notice: Undefined variable: sort_order in c:\workspace\test.php on line 10

The expected output is预期的 output 是

[{"file":"Test.jpg"},{"file":"Hello.jpg"},{"file":"Desert.jpg"}]

I don't know how to get the compare function to properly use the context specific $sort_order function.我不知道如何compare function 以正确使用特定于上下文的$sort_order function。

Edit编辑

I accepted an answer, but for completeness I wanted to post what I finally ended up with that seemed to work.我接受了一个答案,但为了完整起见,我想发布我最终得到的似乎可行的内容。 If anyone wants to post a more elegant solution, I would consider marking it as accepted.如果有人想发布更优雅的解决方案,我会考虑将其标记为已接受。 But here is what I have:但这是我所拥有的:

<?php
    function compare_priority($a, $b) {
        global $g_order, $g_field;
        if ($g_order) {
            $ai = array_search($a[$g_field], $g_order);
            $bi = array_search($b[$g_field], $g_order);
            if ($ai !== false && $bi === false) {
                return -1;
            } else if ($bi !== false && $ai === false) {
                return 1;
            } else if ($ai !== false && $bi !== false) {
                return $ai - $bi;
            }
        }
        return $a[$g_field] < $b[$g_field] ? -1 : 1;
    }

    function sort_priority(&$sort_me, $sort_order, $field) {
        global $g_order, $g_field;
        $g_order = $sort_order;
        $g_field = $field;
        usort($sort_me, "compare_priority");
    }

    $sort_me = array(
       array("file"=>"Z"), 
       array("file"=>"A"), 
       array("file"=>"Y"), 
       array("file"=>"B")
    );
    $sort_order = array("Z", "Y", "C");
    sort_priority($sort_me, $sort_order, "file");
    echo json_encode($sort_me);
?>

You can do the same as you would have done with javascript.您可以像使用 javascript 一样做同样的事情。 usort ( http://ch2.php.net/manual/en/function.usort.php ) allow you to define your custom comparison between elements. usort ( http://ch2.php.net/manual/en/function.usort.php ) 允许您定义元素之间的自定义比较。

I modified your code and it seems to work :我修改了你的代码,它似乎工作:

<?php
    function test() {
        $sort_me = array(
           array("file"=>"Test.jpg"),
           array("file"=>"Desert.jpg"),
           array("file"=>"Hello.jpg")
        );
        global $sort_order;
        $sort_order = array("Test.jpg" , "Hello.jpg", "NotFound.jpg");
        function compare($a, $b) {
            global $sort_order;
            if (is_array($sort_order)) {
                $ai = array_search($a["file"], $sort_order);
                $bi = array_search($b["file"], $sort_order);
                if ($ai !== false && $bi === false) {
                    return -1;
                } else if ($bi !== false && $ai === false) {
                    return 1;
                } else if ($ai !== false && $bi !== false) {
                    return $ai - $bi;
                }
            }
            return $a["file"] < $b["file"] ? -1 : 1;
        }
        usort($sort_me, "compare");
        echo json_encode($sort_me);
    }

    test();
?>

For the cleanest scripting with fewer function calls, use usort() with the spaceship operator.对于具有较少函数调用的最干净的脚本,请将usort()与 spaceship 运算符一起使用。

My technique to follow obeys the 2-step logic (the 1st step containing a condition):我遵循的技术遵循两步逻辑(包含条件的第一步):

  1. sort by the priority array's index values;按优先级数组的索引值排序; if the value is not in the priority array, then use the fallback value (which is higher than the last element's key).如果该值不在优先级数组中,则使用回退值(高于最后一个元素的键)。
  2. when breaking ties that result from the first rule, sort alphabetically当打破由第一条规则产生的联系时,按字母顺序排序

Sample Inputs:样本输入:

$sort_me = [
   ["file" => "Desert.jpg"], 
   ["file" => "What.jpg"], 
   ["file" => "Hello.jpg"], 
   ["file" => "Test.jpg"],
   ["file" => "Goodness.jpg"],
];

$sort_order = ["Test.jpg", "Hello.jpg", "NotFound.jpg"];

Processing Code: ( Demo )处理代码:(演示

$lookup = array_flip($sort_order);
$fallback = count($sort_order);

usort($sort_me, function($a, $b) use ($lookup, $fallback) {
    return [$lookup[$a['file']] ?? $fallback, $a['file']]
           <=>
           [$lookup[$b['file']] ?? $fallback, $b['file']];
});
var_export($sort_me);

Output:输出:

array (
  0 => 
  array (
    'file' => 'Test.jpg',
  ),
  1 => 
  array (
    'file' => 'Hello.jpg',
  ),
  2 => 
  array (
    'file' => 'Desert.jpg',
  ),
  3 => 
  array (
    'file' => 'Goodness.jpg',
  ),
  4 => 
  array (
    'file' => 'What.jpg',
  ),
)

From PHP7.4, you can use arrow function syntax to introduce global variables into the custom function's scope without the use() declaration.从 PHP7.4 开始,您可以使用箭头函数语法将全局变量引入自定义函数的作用域中,而无需use()声明。

usort($sort_me, fn($a, $b) =>
    [$lookup[$a['file']] ?? $fallback, $a['file']]
    <=>
    [$lookup[$b['file']] ?? $fallback, $b['file']]
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM