這是我的第一個方法,旨在最小化循環以達到所需的結果。
代碼:(Demo with 3 different arrays and echo & var_export throughout the process)
// add $array here
$length=sizeof($array);
shuffle($array);
$valcounts=array_count_values($array);
function consec_check($array){
$loops=sizeof($array)-1; // last element will not have right side element for comparison
for($i=0; $i<$loops; ++$i){
if($array[$i]==$array[$i+1]){
return false; // consecutive equal values = invalid
}
}
return true;
}
if(max($valcounts)<=ceil($length/2)){ // if logically possible to fix
while(!consec_check($array)){ // while any two equal elements are consecutive
foreach(array_diff($valcounts,[1]) as $color=>$count){ // only bother with elements that occur more than once
$colorkeys=array_keys($array,$color); // color group keys
for($i=0; $i<$count; ++$i){
if($i>0 && $prevk+1==$colorkeys[$i]){ // identify consecutives elements with same color
if($colorkeys[0]!=0){ // safe to shift {$colorkeys[$i]} to first position
array_unshift($array,array_splice($array,$colorkeys[$i],1)[0]);
}elseif(end($colorkeys)!=$length-1){ // safe to push {$colorkeys[$i]} to the last position
array_push($array,array_splice($array,$colorkeys[$i],1)[0]);
}else{ // no easy option, find a safe location inside array (more frequently used as array length increases)
for($j=0; $j<$count; ++$j){
if($j>0 && $colorkeys[$j]-$prevj>3){ // if 3 off-colors between two elements array_splice($array,$prevj+2,0,array_splice($array,$colorkeys[$i],1));
break;
}
$prevj=$colorkeys[$j];
}
}
$colorkeys=array_keys($array,$color); // update color keys array for continued processing
}
$prevk=$colorkeys[$i];
}
}
}
var_export($array); // valid
}else{
echo "\n\n<a href=\"https://www.youtube.com/watch?v=XAYhNHhxN0A\">Array cannot be made valid.</a>";
}
這裏是使用正則表達式模式我的第二個方法。
代碼:(Demo with 3 different arrays and echo & var_export throughout the process)
shuffle($array);
$string=implode(' ',$array);
$start_length=strlen($string);
foreach(array_unique($array) as $v){
$pullcount=$pushcount1=$pushcount2=0;
$string=preg_replace("/$v (?=$v)/","",$string,-1,$pullcount); // remove the first value of each conflicting pair
$string=preg_replace("/ \K(?<!$v)(?!$v)|^(?!$v)/","$v ",$string,$pullcount,$pushcount1); // foreach removal, re-insert value(s) where valid
if($pullcount<=$pushcount1){
$string=preg_replace("/$(?<!$v)/"," $v",$string,$pullcount-$pushcount1,$pushcount2);
}
if($pullcount!=$pushcount1+$pushcount2){
echo "failure while replacing $v $pullcount & ",$pushcount1+$pushcount2,"\n";
break;
}else{
echo "successfully replaced $pullcount conflicts for $v\n";
}
}
if($start_length==strlen($string)){
$array=explode(" ",$string);
var_export($array);
}else{
echo "\n<a href=\"https://www.youtube.com/watch?v=XAYhNHhxN0A\">Array cannot be made valid.</a>";
}
我的第二個方法勝簡潔,但它可能無法在其他情況下,值包含空格或當值是另一個值的子串值得信賴。
這兩種方法避免了無限循環的可能性,並且會指示數組是否無效。
那麼爲數組中的數據計數[看看'array_count_values()']手冊(http://php.net/manual/en/function.array-count-values.php) – RiggsFolly
你知道它是否總是可以解決的,例如像起點永遠不會是(紅色,紅色,紅色,藍色)? – bumperbox
該數組將始終以紅,綠,藍的順序列出,並以任何一個結束。 @mickmackusa我需要它的PHP,所以我問它在這裏。 –