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

PHP重新排序包含重复项的数组,以在重复项之间建立/保持距离,php,arrays,sorting,duplicates,Php,Arrays,Sorting,Duplicates,想象一下包含元素的阵列-零售、零售、娱乐、娱乐 我需要对它们进行排序,这样就不会有重复的元素彼此相邻,但总体顺序可能非常随机-零售、娱乐、零售、娱乐 我已经尝试了uasort(),但无法退出,因为它会比较所有可能的对,我想我应该存储在外部数组中,已经对检查过的元素进行排序,以了解在哪种情况下返回-或+integer,是否可以移动多个位置,即返回-2或uasort回调中的smthing 输入数组$Input=[“零售”、“零售”、“食品”、“慈善”、“娱乐”、“娱乐”、“交通”、“化妆品”] 输出

想象一下包含元素的阵列-零售、零售、娱乐、娱乐

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

我已经尝试了uasort(),但无法退出,因为它会比较所有可能的对,我想我应该存储在外部数组中,已经对检查过的元素进行排序,以了解在哪种情况下返回-或+integer,是否可以移动多个位置,即返回-2或uasort回调中的smthing

输入数组
$Input=[“零售”、“零售”、“食品”、“慈善”、“娱乐”、“娱乐”、“交通”、“化妆品”]

输出数组应该像
$Output=[“零售”、“食品”、“零售”、“慈善”、“娱乐”、“交通”、“娱乐”、“化妆品”]

我的尝试:


我找到了一种排序方法,也许任何人都有更好的想法:

受此启发,我决定将数据压缩成一个值和计数的关联数组,然后将数组从最频繁到最不频繁排序。我循环遍历数组,只处理第一个元素。我将该值添加到输出数组中,然后减少其计数并将其移动到下一个元素之后的位置

我已经建立了一个故障保护,以防止在无法获得完美结果时出现无限循环

如果没有值多次出现,则永远不会进入循环

代码:()

产出:

Array
(
    [0] => Retail
    [1] => Food
    [2] => Retail
    [3] => 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',
)
---

我试着让排序数组靠近输入数组。 首先,我从数组中删除所有非匹配元素,然后尝试插入它们。 如果剩下任何元素,我将遍历阵列,将它们插入任何合适的位置,避免无休止的循环。结果得到2个数组,一个已排序,另一个找不到拟合位置:

 $input =  ['Charity','Retail','Retail','Retail','Retail', 'Retail' ,'Retail',  'Charity',  'Charity', 'Charity','a' ];

$laRest     = [];
$sorted     = [];
$laNoPlace  = [];

while(count($input) >0) {
    for ($i = 0; $i < count($laRest); $i++) {
        if(isset($laRest[$i]) && $laRest[$i] != end($sorted)) {
            $sorted[] = $laRest[$i];
            unset($laRest[$i]);
        }
    }
    $laRest     = array_values($laRest);
    $lsElement  = array_shift($input);
    if (end($sorted) != $lsElement) {
        $sorted[] = $lsElement;
    }
    else {
        $laRest[] = $lsElement;
    }
}

if(count($laRest) >0) {
    while(count($laRest) >0) {
        $lsElement = array_shift($laRest);
        for ($i = 0; $i < count($sorted); $i++) {
            if($i != 0 && $sorted[$i] != $lsElement && !isset($sorted[$i+1]) && $lsElement !='') {//end
                array_push($sorted, $lsElement);
                $lsElement = '';
            }
            if($i != 0 && $sorted[$i] != $lsElement && isset($sorted[$i+1]) && $sorted[$i+1] != $lsElement && $lsElement !='') {
                $lsStart = array_slice($sorted, 0, $i+1);
                $lsEnd   = array_slice($sorted , $i+1);
                $sorted  = array_merge($lsStart,  array($lsElement), $lsEnd);
                $lsElement = '';
            } 
            if($i == 0 && $sorted[$i] != $lsElement && $lsElement !='') {//start
              array_unshift($sorted, $lsElement);
              $lsElement = '';
            } 
        }
        if($lsElement != '') {
            $laNoPlace[] = $lsElement;
        }
    }
}

print_r($sorted);
echo "<HR>";
print_r($laNoPlace);
echo "<HR>";
$input=[“慈善”、“零售”、“零售”、“零售”、“零售”、“零售”、“零售”、“慈善”、“慈善”、“慈善”、“慈善”、“a”];
$laRest=[];
$sorted=[];
$laNoPlace=[];
而(计数($input)>0){
对于($i=0;$i0){
而(计数($laRest)>0){
$lsElement=数组移位($laRest);
对于($i=0;$i”;
打印(laNoPlace);
回声“
”;
稍后我将添加和上一次尝试……您是否确定要获得该特定的输出订单,或者是否也可以接受没有两个名称相同的项目的任何其他订单?是否需要保留尽可能多的原始顺序,或者(比如)以完全相反的顺序显示的整个输出数组也可以接受?在你的需求无法满足的情况下,比如输入是[foo,foo,bar,foo]时,你想如何处理这些事情?不,顺序可以是随机的,但如果顺序尽可能接近原始顺序(减去)重复的话会更好。我称之为“洗牌”,而不是“排序”。几乎所有排序算法都只比较两个项目的排名。这显然需要比较两个以上的项目。但是,这是一个多么有趣的问题。如果您的输入数据使所需的排序变得不可能,例如f.e.
['Retail','Retail','Food','Retail']
Shuffle不应该被视为alogorithm中一种高效/有效的技术。Bravo,它在这方面做得很好:
['Peter','Peter','Paul','Paul','Paul','Paul']
。这就是我要去的地方,但我认为edge cases仍然会绊倒它。我在寻找某种“排斥”算法。另一个附带案例:['Charity','Entertainment','Retail','Retail','Retail'];抱歉打扰了不,一点也不麻烦。我很感激举报。我不能暂时删除我的答案,不是因为它被接受,而是我会在晚餐/家庭时间后修复它。干杯@Fat@Fat谢谢,我添加了另一个arsort来更正逻辑
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',
)
---
 $input =  ['Charity','Retail','Retail','Retail','Retail', 'Retail' ,'Retail',  'Charity',  'Charity', 'Charity','a' ];

$laRest     = [];
$sorted     = [];
$laNoPlace  = [];

while(count($input) >0) {
    for ($i = 0; $i < count($laRest); $i++) {
        if(isset($laRest[$i]) && $laRest[$i] != end($sorted)) {
            $sorted[] = $laRest[$i];
            unset($laRest[$i]);
        }
    }
    $laRest     = array_values($laRest);
    $lsElement  = array_shift($input);
    if (end($sorted) != $lsElement) {
        $sorted[] = $lsElement;
    }
    else {
        $laRest[] = $lsElement;
    }
}

if(count($laRest) >0) {
    while(count($laRest) >0) {
        $lsElement = array_shift($laRest);
        for ($i = 0; $i < count($sorted); $i++) {
            if($i != 0 && $sorted[$i] != $lsElement && !isset($sorted[$i+1]) && $lsElement !='') {//end
                array_push($sorted, $lsElement);
                $lsElement = '';
            }
            if($i != 0 && $sorted[$i] != $lsElement && isset($sorted[$i+1]) && $sorted[$i+1] != $lsElement && $lsElement !='') {
                $lsStart = array_slice($sorted, 0, $i+1);
                $lsEnd   = array_slice($sorted , $i+1);
                $sorted  = array_merge($lsStart,  array($lsElement), $lsEnd);
                $lsElement = '';
            } 
            if($i == 0 && $sorted[$i] != $lsElement && $lsElement !='') {//start
              array_unshift($sorted, $lsElement);
              $lsElement = '';
            } 
        }
        if($lsElement != '') {
            $laNoPlace[] = $lsElement;
        }
    }
}

print_r($sorted);
echo "<HR>";
print_r($laNoPlace);
echo "<HR>";