1

私が持っていると言う:

$array = (1,1,1,1,2,2,2,2,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

私が達成しようとしているのは、要素を均等に並べ替えることです。

PHP の関数 shuffle() は、同じ数字の間にある程度の距離が必要なため、ここには適合しません。したがって、1 は配列の先頭、中間、および末尾のどこかになければなりません。

Fisher-Yates_shuffleアルゴリズムについてググってみましたが、shuffle() とまったく同じように動作するようです。

前もって感謝します!

4

1 に答える 1

2

これはあなたが求めるものに近いと思います: 配列内の項目の定数で、適度に均一な分布。

// The input array. 0s are regarded as blanks.
$array = array(1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

// Count the times each item occurs. PHP will probably have a function for that, but I don't know.
$counter = array();
foreach ($array as $item)
{
  // Zeros are infill. Don't process them now, only process the other numbers and
  // the zeros will occupy the remaining space.
  if ($item === 0)
    continue;

  if (!array_key_exists($item, $counter))
    $counter[$item] = 0;
  $counter[$item]++;
}

// Reverse sort by quantity. This results in the best distribution.
arsort($counter);

// Pre-fill a new array with zeros.
$resultCount = count($array);
$result = array_fill(0, $resultCount, 0);

// Distribute the items in the array, depending on the number of times they occur.
foreach ($counter as $item => $count)
{
  // Determine the division for this item, based on its count.
  $step = $resultCount / $count;

  // Add the item the right number of times.
  for ($i = 0; $i < $count; $i++)
  {
    // Start with the index closest to the preferred one (based on the calculated step).
    $index = 0;
    $startIndex = (int)($step * $i);
    // Count up until a right index is found.
    for ($index = $startIndex; $index < $resultCount; $index++)
    {
      if ($result[$index] === 0)
      {
        $result[$index] = $item;
        break;
      }
    }
    // If no proper index was found, count fown from the starting index.
    if ($index === $resultCount)
    {
      for ($index = $startIndex; $index >= 0; $index--)
      {
        if ($result[$index] === 0)
        {
          $result[$index] = $item;
          break;
        }
      }
    }

    // Still no proper index found, that shouldn't be possible. There's always room.
    if ($index === -1)
    {
      throw new Exception('This cannot not happen');
    }
  }
}

var_dump($result);

配列の場合:

1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

戻り値:

3,2,1,0,3,0,0,0,3,0,2,1,3,0,0,0,3,0,0,0,0,3,2,1,0,3,0,0,0,3,0,2,1,3,0,0,0,3,0,0,0,0

配列の場合:

1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0

戻り値:

4,4,3,4,3,4,2,4,3,4,2,4,3,4,1,4,3,4,1,4,0,4,4,3,4,3,4,2,4,3,4,2,4,3,4,1,4,3,4,1,4,0

これはきちんとした分布だと思います。中間配列をソートするアイデアを提供してくれた datdo に感謝します。

于 2012-11-21T17:45:54.677 に答える