安排一组不同的组,以便它的元素没有来自类似组的邻居

时间:2016-04-05 00:40:40

标签: php arrays graph-coloring

我有一个数组可以通过其中一个属性分成3个不同的组:

$shuffleMeGood = array(
    0 => array('id' => '1', 'group' => 'banana'),
    1 => array('id' => '2', 'group' => 'banana'),
    2 => array('id' => '3', 'group' => 'banana'),
    3 => array('id' => '4', 'group' => 'airplane'),
    4 => array('id' => '5', 'group' => 'coconut'),
    5 => array('id' => '6', 'group' => 'coconut')
    ...
);

组的大小可以变化,可以有7个椰子元素和5个飞机元素等等。如何以同一组中没有或最不可能出现的邻居的方式对阵列进行洗牌?

我试图将它们分成3个不同的数组,然后按照它们的大小比例再次合并它们。但是对于比率接近的组,我最终会在一个组中有一个组。

1 个答案:

答案 0 :(得分:0)

编辑:根据OP对如何处理剩余项目的评论调整答案。保留我原来的答案。

我们将通过计算每个组中可以放入的数量并使用一些中间数组来均匀地分配最大的组:

<?php
// Your array changed to PHP with some added items
$a = array(
    array(
        'id'=>1,
        'group'=>'banana'
    ),
    array(
        'id'=>2,
        'group'=>'banana'
    ),
    array(
        'id'=>3,
        'group'=>'banana'
    ),
    array(
        'id'=>4,
        'group'=>'airplane'
    ),
    array(
        'id'=>5,
        'group'=>'coconut'
    ),
    array(
        'id'=>6,
        'group'=>'coconut'
    ),
    array(
        'id'=>7,
        'group'=>'coconut'
    ),
    array(
        'id'=>8,
        'group'=>'coconut'
    ),
    array(
        'id'=>9,
        'group'=>'coconut'
    ),
    array(
        'id'=>10,
        'group'=>'coconut'
    ),
);

// We want to know each of group there are
// We also want to arrange the items in a new "perGroup" array.
$counts = array();
$perGroup = array();
foreach($a as $key=>$value){
    // Avoid PHP undefined notices
    if(isset($counts[$value['group']])){
        $counts[$value['group']]++;

    }else{
        $counts[$value['group']] = 1;
    }

    // Avoid PHP undefined notices
    if(isset($perGroup[$value['group']])){
        $perGroup[$value['group']][] = $value;
    }else{
        $perGroup[$value['group']] = array();
        $perGroup[$value['group']][] = $value;
    }
}

// Sort the count from largest to lowest
arsort($counts);
// Get all the group names
$keys = array_keys($counts);
// We'll have as many unique groups as the SECOND largest item.
$nbOfUniques = $counts[$keys[1]];
// Calculate how many of the largest we need to put in each unique
$nbOfLargestPerUnique = ceil($counts[$keys[0]] / $nbOfUniques);
// Get the largest group name for easier use
$largestGroupName = $keys[0];

$finalArray = array();
// Loop for how many unique groups we have
for ($i = 1; $i <= $nbOfUniques; $i++) {
    // For each group...
    foreach($keys as $k=>$v){
        // If its the largest
        if($v == $largestGroupName){
            // Add as many as needed
            for ($j = 1; $j <= $nbOfLargestPerUnique; $j++) {
                // Make sure we actually have an item, as the number is not always exact.
                // Using array_shift() to reduce our array
                if(($item = array_shift($perGroup[$v])) !== NULL){
                    $finalArray[] = $item;
                }
            }
        }else{
            // Not the largest group, just add one
            if(($item = array_shift($perGroup[$v])) !== NULL){
                $finalArray[] = $item;
            }
        }
    }
}

echo '<pre>';
var_dump($finalArray);
echo '</pre>';
?>

<强> ORIGINAL: 我将使用一个带有两个数组的递归函数:最后一个,以及在我们处理所有数据之前变得越来越小的初始数据的副本:

<?php
// Your array changed to PHP with some added items
$a = array(
    array(
        'id'=>1,
        'group'=>'banana'
    ),
    array(
        'id'=>2,
        'group'=>'banana'
    ),
    array(
        'id'=>3,
        'group'=>'banana'
    ),
    array(
        'id'=>4,
        'group'=>'airplane'
    ),
    array(
        'id'=>5,
        'group'=>'coconut'
    ),
    array(
        'id'=>6,
        'group'=>'coconut'
    ),
    array(
        'id'=>7,
        'group'=>'coconut'
    ),
    array(
        'id'=>8,
        'group'=>'coconut'
    ),
    array(
        'id'=>9,
        'group'=>'coconut'
    ),
    array(
        'id'=>10,
        'group'=>'coconut'
    ),
);

// Our recursive function
// $array is the array to be ordered (in our case, $a)
// $orderedArray is needed for the recusivity part
function orderArray($array, $orderedArray = array()){
    // Remember the last processed group
    $lastGroup = '';

    // Loop on all $array's items
    foreach($array as $key=>$value){
        // If NOT the same as the last group
        if($value['group'] != $lastGroup){
            // Add it to our orderedArray
            $orderedArray[] = $value;
            // Remember its group
            $lastGroup = $value['group'];
            // Remove it from the original array, as it has already been processed
            unset($array[$key]);
        }
    }
    // There are still items to be processed
    if(count($array) > 0){
        // Call ourselves again, with the same arrays
        return orderArray($array, $orderedArray);
    }else{
        // Done processing, return the $orderedArray
        return $orderedArray;
    }
}

echo '<pre>';
var_dump(orderArray($a));
echo '</pre>';
?>

然而,如果一个群体明显超过其他群体(例如我的例子中的椰子),那么最终你会得到一堆椰子。

希望它有所帮助。