繁体   English   中英

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

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

我有一个这样的数组:

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

我想根据文件属性按字母顺序对这个数组进行排序。 为了使事情复杂化,我有一个可选数组:

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

该数组将指定一些用户定义的排序。 这些数组元素具有优先级,如果找到它们将按该顺序放置。 $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.

如何使用 PHP 做到这一点?

编辑

我尝试了一些东西,但没有成功。 (再次修改,将逻辑放到一个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);
?>

这输出

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

预期的 output 是

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

我不知道如何compare function 以正确使用特定于上下文的$sort_order function。

编辑

我接受了一个答案,但为了完整起见,我想发布我最终得到的似乎可行的内容。 如果有人想发布更优雅的解决方案,我会考虑将其标记为已接受。 但这是我所拥有的:

<?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);
?>

您可以像使用 javascript 一样做同样的事情。 usort ( http://ch2.php.net/manual/en/function.usort.php ) 允许您定义元素之间的自定义比较。

我修改了你的代码,它似乎工作:

<?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();
?>

对于具有较少函数调用的最干净的脚本,请将usort()与 spaceship 运算符一起使用。

我遵循的技术遵循两步逻辑(包含条件的第一步):

  1. 按优先级数组的索引值排序; 如果该值不在优先级数组中,则使用回退值(高于最后一个元素的键)。
  2. 当打破由第一条规则产生的联系时,按字母顺序排序

样本输入:

$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"];

处理代码:(演示

$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);

输出:

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',
  ),
)

从 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