2017-04-04 92 views
1

我需要以隨機順序對數組進行隨機混合,而不會有兩個併發值相同。重新排列數組,使PHP中沒有相鄰值相同

$array("red", "green", "blue", "red", "green", "blue", "red", "green", "blue", etc); 

輸出應該是包含所有值的隨機順序的任何有效數組,而不是兩個值彼此相鄰。

有效的選項是這樣的:

$array("blue", "red", "blue", "green", "red", "blue", "green"); 

我在想如何計算的「紅」的量,「藍色」和「綠色」

array_count_values($array); 
array_count_values($array)["red"]; 
array_count_values($array)["green"]; 
array_count_values($array)["blue"]; 

然後可能創建一個使用數組每個字符串的可用量。

+1

那麼爲數組中的數據計數[看看'array_count_values()']手冊(http://php.net/manual/en/function.array-count-values.php) – RiggsFolly

+0

你知道它是否總是可以解決的,例如像起點永遠不會是(紅色,紅色,紅色,藍色)? – bumperbox

+0

該數組將始終以紅,綠,藍的順序列出,並以任何一個結束。 @mickmackusa我需要它的PHP,所以我問它在這裏。 –

回答

1

這是我的第一個方法,旨在最小化循環以達到所需的結果。

代碼:(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>"; 
} 

我的第二個方法勝簡潔,但它可能無法在其他情況下,值包含空格或當值是另一個值的子串值得信賴。

這兩種方法避免了無限循環的可能性,並且會指示數組是否無效。

+0

非常感謝,這會幫助我進一步得到更多:) –

相關問題