PHP重新排序包含重复项目的数组以在重复项目之间保持距离

想象一下包含元素的数组 - 零售、零售、娱乐、娱乐


我需要对它们进行排序,这样就不会有重复的元素彼此相邻,但总体顺序可能相当随机-零售、娱乐、零售、娱乐


我已经尝试过uasort(),但无法退出找到从哪里开始,因为它会比较所有可能的对我想我应该喜欢存储在外部数组中已经排序检查的元素以知道在哪种情况下返回 - 或 + integer,并且是可以移动多个位置,即return -2;或者 uasort 回调中的东西


输入数组$input = ['Retail', 'Retail', 'Food', 'Charity', 'Entertainment', 'Entertainment', 'Transport', 'Cosmetics'];


输出数组应该看起来像$output = ['Retail', 'Food', 'Retail', 'Charity', 'Entertainment', 'Transport', 'Entertainment', 'Cosmetics'];


我的尝试:


<?php


$input  = ['Retail', 'Retail', 'Food', 'Charity', 'Entertainment', 'Entertainment', 'Transport', 'Cosmetics'];

$sorted = [];


uasort(

    $input,

    static function ($a, $b) use (&$sorted) {

        $is_a_sorted = in_array($a, $sorted, true);

        $is_b_sorted = in_array($b, $sorted, true);


        switch (true) {

            case !$is_a_sorted && !$is_b_sorted:

                $sorted[] = $a;

                $sorted[] = $b;

                return -1;

            case $is_a_sorted || $is_b_sorted:

                return 1;

            default:

                return 0;

        }

    }

);


print_r($input);

结果是:


Array ( [7] => 化妆品 [4] => 娱乐 [6] => 交通 [5] => 娱乐 [2] => 食品 [3] => 慈善 [0] => 零售 [1] => 零售)


月关宝盒
浏览 85回答 3
3回答

萧十郎

我决定将数据压缩为值和计数的关联数组,然后对数组从出现次数最多的到最少出现的进行排序。我循环遍历数组并仅处理第一个元素。我将值添加到输出数组,然后递减其计数并将其移动到下一个元素之后的位置。我内置了故障保护功能,以防止在不可能获得完美结果时出现无限循环。如果没有值出现多次,则永远不会进入循环。代码:(演示)function valueSeparator(array $array) {    $maxIterations = count($array);    $counted = array_count_values($array);    arsort($counted);    $iteration = 0;    $result = [];    while (max($counted) > 1 && $iteration < $maxIterations) {        $count = reset($counted);        $value = key($counted);        $result[] = $value;        unset($counted[$value]);        arsort($counted);        if ($count > 1) {            $counted = array_merge(                array_splice($counted, 0, 1),                [$value => $count - 1],                $counted            );        }        ++$iteration;    }    array_push($result, ...array_keys($counted));    var_export($result);}foreach ($arrays as $array) {    valueSeparator($array);    echo "\n---\n";}测试用例:$arrays = [    ['Retail', 'Retail', 'Food', 'Food', 'Retail'],    ['Retail', 'Retail', 'Food', 'Charity', 'Entertainment', 'Entertainment', 'Transport', 'Cosmetics'],    ['Food'],    ['Retail', 'Retail', 'Food', 'Retail'],    ['Retail', 'Retail', 'Retail', 'Food', 'Food', 'Food', 'Charity', 'Charity', 'Charity'],    ['Charity', 'Entertainment', 'Retail', 'Retail' ,'Retail']];输出:array (  0 => 'Retail',  1 => 'Food',  2 => 'Retail',  3 => 'Food',  4 => 'Retail',)---array (  0 => 'Retail',  1 => 'Entertainment',  2 => 'Food',  3 => 'Retail',  4 => 'Entertainment',  5 => 'Charity',  6 => 'Transport',  7 => 'Cosmetics',)---array (  0 => 'Food',)---array (  0 => 'Retail',  1 => 'Food',  2 => 'Retail',  3 => 'Retail',)---array (  0 => 'Retail',  1 => 'Food',  2 => 'Charity',  3 => 'Retail',  4 => 'Food',  5 => 'Charity',  6 => 'Retail',  7 => 'Food',  8 => 'Charity',)---array (  0 => 'Retail',  1 => 'Charity',  2 => 'Retail',  3 => 'Entertainment',  4 => 'Retail',)---

慕码人2483693

我尝试将排序数组保持在靠近输入数组的位置。首先,我从数组中删除任何不适合的元素,然后尝试稍后插入它们。如果剩下任何元素,我会遍历数组,将它们插入到任何合适的位置,避免无限循环。结果你得到 2 个数组,一个已排序,另一个找不到合适的位置:&nbsp;$input =&nbsp; ['Charity','Retail','Retail','Retail','Retail', 'Retail' ,'Retail',&nbsp; 'Charity',&nbsp; 'Charity', 'Charity','a' ];$laRest&nbsp; &nbsp; &nbsp;= [];$sorted&nbsp; &nbsp; &nbsp;= [];$laNoPlace&nbsp; = [];while(count($input) >0) {&nbsp; &nbsp; for ($i = 0; $i < count($laRest); $i++) {&nbsp; &nbsp; &nbsp; &nbsp; if(isset($laRest[$i]) && $laRest[$i] != end($sorted)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sorted[] = $laRest[$i];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unset($laRest[$i]);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; $laRest&nbsp; &nbsp; &nbsp;= array_values($laRest);&nbsp; &nbsp; $lsElement&nbsp; = array_shift($input);&nbsp; &nbsp; if (end($sorted) != $lsElement) {&nbsp; &nbsp; &nbsp; &nbsp; $sorted[] = $lsElement;&nbsp; &nbsp; }&nbsp; &nbsp; else {&nbsp; &nbsp; &nbsp; &nbsp; $laRest[] = $lsElement;&nbsp; &nbsp; }}if(count($laRest) >0) {&nbsp; &nbsp; while(count($laRest) >0) {&nbsp; &nbsp; &nbsp; &nbsp; $lsElement = array_shift($laRest);&nbsp; &nbsp; &nbsp; &nbsp; for ($i = 0; $i < count($sorted); $i++) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if($i != 0 && $sorted[$i] != $lsElement && !isset($sorted[$i+1]) && $lsElement !='') {//end&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array_push($sorted, $lsElement);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $lsElement = '';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if($i != 0 && $sorted[$i] != $lsElement && isset($sorted[$i+1]) && $sorted[$i+1] != $lsElement && $lsElement !='') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $lsStart = array_slice($sorted, 0, $i+1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $lsEnd&nbsp; &nbsp;= array_slice($sorted , $i+1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $sorted&nbsp; = array_merge($lsStart,&nbsp; array($lsElement), $lsEnd);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $lsElement = '';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if($i == 0 && $sorted[$i] != $lsElement && $lsElement !='') {//start&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; array_unshift($sorted, $lsElement);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $lsElement = '';&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; if($lsElement != '') {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $laNoPlace[] = $lsElement;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}print_r($sorted);echo "<HR>";print_r($laNoPlace);echo "<HR>";

繁星coding

我找到了一种排序方法,也许有人有更好的想法:<?php$array&nbsp; = ['Retail', 'Retail', 'Food', 'Charity', 'Entertainment', 'Entertainment', 'Transport', 'Cosmetics'];$sorted = [];while (!empty($array)) {&nbsp; &nbsp; $current = current($array);&nbsp; &nbsp; if (end($sorted) !== $current) {&nbsp; &nbsp; &nbsp; &nbsp; $sorted[] = $current;&nbsp; &nbsp; &nbsp; &nbsp; array_splice($array, key($array), 1);&nbsp; &nbsp; }&nbsp; &nbsp; $next = next($array);&nbsp; &nbsp; if (!$next) {&nbsp; &nbsp; &nbsp; &nbsp; reset($array);&nbsp; &nbsp; &nbsp; &nbsp; shuffle($array);&nbsp; &nbsp; }}print_r($sorted);输出:Array(&nbsp; &nbsp; [0] => Retail&nbsp; &nbsp; [1] => Food&nbsp; &nbsp; [2] => Charity&nbsp; &nbsp; [3] => Entertainment&nbsp; &nbsp; [4] => Transport&nbsp; &nbsp; [5] => Entertainment&nbsp; &nbsp; [6] => Cosmetics&nbsp; &nbsp; [7] => Retail)另一个输入示例:$array&nbsp; = ['Retail', 'Retail', 'Retail', 'Retail', 'Retail', 'Food', 'Charity', 'Charity', 'Charity', 'Entertainment', 'Entertainment', 'Transport', 'Cosmetics'];输出:Array(&nbsp; &nbsp; [0] => Retail&nbsp; &nbsp; [1] => Food&nbsp; &nbsp; [2] => Retail&nbsp; &nbsp; [3] => Charity&nbsp; &nbsp; [4] => Retail&nbsp; &nbsp; [5] => Charity&nbsp; &nbsp; [6] => Retail&nbsp; &nbsp; [7] => Charity&nbsp; &nbsp; [8] => Entertainment&nbsp; &nbsp; [9] => Transport&nbsp; &nbsp; [10] => Entertainment&nbsp; &nbsp; [11] => Cosmetics&nbsp; &nbsp; [12] => Retail)针对特殊场合的更新代码,例如当输入是这样的时,['Retail', 'Retail', 'Food', 'Retail']在我的情况下是合理且可接受的:<?php$array&nbsp; = ['Retail', 'Retail', 'Food', 'Retail'];$sorted = [];$tries = 0;$maxTries = count($array);while (!empty($array) && $tries <= $maxTries) {&nbsp; &nbsp; $current = current($array);&nbsp; &nbsp; if (end($sorted) !== $current) {&nbsp; &nbsp; &nbsp; &nbsp; $sorted[] = $current;&nbsp; &nbsp; &nbsp; &nbsp; array_splice($array, key($array), 1);&nbsp; &nbsp; }&nbsp; &nbsp; $next = next($array);&nbsp; &nbsp; if (!$next) {&nbsp; &nbsp; &nbsp; &nbsp; reset($array);&nbsp; &nbsp; &nbsp; &nbsp; shuffle($array);&nbsp; &nbsp; &nbsp; &nbsp; $tries++;&nbsp; &nbsp; }}if (!empty($array)) {&nbsp; &nbsp; array_push($sorted, ...$array);}print_r($sorted);输出:Array(&nbsp; &nbsp; [0] => Retail&nbsp; &nbsp; [1] => Food&nbsp; &nbsp; [2] => Retail&nbsp; &nbsp; [3] => Retail)
打开App,查看更多内容
随时随地看视频慕课网APP