从数组中获取给定数量元素的所有唯一组合


Get all unique combinations from array for a given number of elements

我想有一种方法来获得给定数组长度的所有给定数字的所有组合。在我的项目中,数组大小通常为7。所以我写了一个这样的测试代码,看看我是否能得到所有需要的组合。重要的是,每个结果数组都必须是唯一的,并且最大数组大小必须为7。

<?php
$numbers = [1, 2, 3, 4, 5, 6, 7];
$arraysize = 7;
$subset = [];
$count = count($numbers);
for ($i = 0; $i < $count; $i++) {
    $subset[] = $numbers[$i];
}
for ($i=0; $i < $count; $i++) {
    for ($j=$i; $j < $count; $j++) {
        $subset[] = $numbers[$i] . $numbers[$j];
    }
}
for ($i=0; $i < $count; $i++) {
    for ($j=$i; $j < $count; $j++) {
        for ($k=$j; $k < $count; $k++) {
            $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k];
        }
    }
}
for ($i=0; $i < $count; $i++) {
    for ($j=$i; $j < $count; $j++) {
        for ($k=$j; $k < $count; $k++) {
            for ($l=$k; $l < $count; $l++) {
                $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l];
            }
        }
    }
}
for ($i=0; $i < $count; $i++) {
    for ($j=$i; $j < $count; $j++) {
        for ($k=$j; $k < $count; $k++) {
            for ($l=$k; $l < $count; $l++) {
                for ($m=$l; $m < $count; $m++) {
                    $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l] . $numbers[$m];
                }
            }
        }
    }
}
for ($i=0; $i < $count; $i++) {
    for ($j=$i; $j < $count; $j++) {
        for ($k=$j; $k < $count; $k++) {
            for ($l=$k; $l < $count; $l++) {
                for ($m=$l; $m < $count; $m++) {
                    for ($n=$m; $n < $count; $n++) {
                        $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l] . $numbers[$m] . $numbers[$n];
                    }
                }
            }
        }
    }
}
for ($i=0; $i < $count; $i++) {
    for ($j=$i; $j < $count; $j++) {
        for ($k=$j; $k < $count; $k++) {
            for ($l=$k; $l < $count; $l++) {
                for ($m=$l; $m < $count; $m++) {
                    for ($n=$m; $n < $count; $n++) {
                        for ($o=$n; $o < $count; $o++) {
                            $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l] . $numbers[$m] . $numbers[$n] . $numbers[$o];
                        }
                    }
                }
            }
        }
    }
}
echo "<pre>";
print_r($subset);
echo "</pre>";
?>

当我运行这段代码时,我得到了我想要的组合(我把组合做成字符串以清楚地看到结果,但通常$subset数组中的每个结果项都必须是数组)有了这个代码,我可以得到所有唯一的组合。

但是正如你所看到的,这个代码是丑陋的。我试图把它变成一个递归函数,但我失败了。有人能给我指一个正确的方向,让我得到完全相同的结果吗?($subset数组中的每个项通常都必须是包含数字的数组)

您可以使用简化此逻辑(并使代码不那么难看),而无需递归

for ($i = 0; $i < $count; $i++) {
    $subset[] = $numbers[$i];
    for ($j=$i; $j < $count; $j++) {
        $subset[] = $numbers[$i] . $numbers[$j];
        for ($k=$j; $k < $count; $k++) {
            $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k];
            for ($l=$k; $l < $count; $l++) {
                $subset[] = $numbers[$i] . $numbers[$j] . $numbers[$k] . $numbers[$l];
            }
        }
    }
}

即使数组中有重复的数字,以下内容也适用于所有情况

$array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14);  
 sort($array);  //in case it 's not sorted
 $array = array_slice($array,-7);   
 $num = count($array );  
  $total = pow(2, $num);
  $result= array();
  $element='';
   for ($i = 0; $i < $total; $i++) 
    {      
          for ($j = 0; $j < $num; $j++) 
              {                 
                 if (pow(2, $j) & $i) 
                 {
                 $element=$element.$array [$j];                 
                 }                                       
              }
              $result[]=$element;
              $element=''; 
      }
      print_r($result);

此实现返回所有项的所有组合(77=823542个7项的组合):

function combine_all(array $numbers) {
    $count = count($numbers);
    $result = array_map('strval', $numbers);
    for($i = 1; $i < $count; ++$i) {
        $combinations = array_slice($result, pow($count, $i-1));
        foreach($numbers as $number) {
            foreach($combinations as $combination) {
                $result[] = $number . ',' . $combination;
            }
        }
    }
    return $result;
}

当使用print_r输出数据时,它的执行速度可能非常慢:

$array = array_fill(0, pow(7,7), '');
$t = microtime(true);
echo '<pre>';
print_r($array);
echo '</pre>';
echo microtime(true) - $t;
// 0.75329303741455

$t = microtime(true);
echo '<pre>';
print_r( combine_all(array(1,2,3,4,5,6,7)) );
echo '</pre>';
echo microtime(true) - $t;
// 1.7037351131439

$t = microtime(true);
combine_all(array(1,2,3,4,5,6,7));
echo microtime(true) - $t;
//0.75869607925415

要限制项目编号,请使用array_slice函数:

combine_all(array_slice($numbers, 0, 7));

如果你真的想要一个递归函数,你可以这样做:

function combine_all(array $numbers, $cnt=null, $baseCombination=null) {
    if( $baseCombination === null ) {
        $cnt = count($numbers);
    }
    if( $cnt > 0 ) {
        $result = array();
        foreach($numbers as $number) {
            $combination = $number . ',' . $baseCombination;
            $result[] = $combination;
            $result = array_merge($result, combine_all($numbers, $cnt-1, $combination));
        }
        return $result;
    }
    return array();
}

但这需要太多的记忆。

我终于找到了一种添加递归函数的方法,可以根据给定的数字创建唯一的组合:

$numbers = [1, 2, 3, 4, 5, 6, 7];
function subsetSumRecursive($numbers, $arraySize, $level = 1, $i = 0, $addThis = [])
{
    // If this is the last layer, use a different method to pass the number.
    if ($level == $arraySize) {
        $result = [];
        for (; $i < count($numbers); $i++) {
            $result[] = array_merge($addThis, array($numbers[$i]));
        }
        return $result;
    }
    $result = [];
    $nextLevel = $level + 1;
    for (; $i < count($numbers); $i++) {
        // Add the data given from upper level to current iterated number and pass
        // the new data to a deeper level.
        $newAdd = array_merge($addThis, array($numbers[$i]));
        $temp = subsetSumRecursive($numbers, $arraySize, $nextLevel, $i, $newAdd);
        $result = array_merge($result, $temp);
    }
    return $result;
}
echo "<pre>";
print_r(subsetSumRecursive($numbers, 7));
echo "</pre>";