PHP查找数组的所有(有点)唯一组合

Posted

技术标签:

【中文标题】PHP查找数组的所有(有点)唯一组合【英文标题】:PHP Find All (somewhat) Unique Combinations of an Array 【发布时间】:2013-04-25 00:03:48 【问题描述】:

我整天都在看 php 数组排列/组合问题.. 仍然无法弄清楚:/

如果我有一个类似的数组:

20 //key being 0    
20 //key being 1    
22 //key being 2    
24 //key being 3

我需要这样的组合:

20, 20, 22 //keys being 0 1 2    
20, 20, 24 //keys being 0 1 3    
20, 22, 24 //keys being 0 2 3
20, 22, 24 //keys being 1 2 3

我目前拥有的代码:

20, 22, 24

因为它不想重复 20 次……但这正是我所需要的!

这是我的代码。直接来自Php recursion to get all possibilities of strings

function getCombinations($base,$n)

$baselen = count($base);
if($baselen == 0)
    return;

    if($n == 1)
        $return = array();
        foreach($base as $b)
            $return[] = array($b);
        
        return $return;
    else
        //get one level lower combinations
        $oneLevelLower = getCombinations($base,$n-1);

        //for every one level lower combinations add one element to them that the last element of a combination is preceeded by the element which follows it in base array if there is none, does not add
        $newCombs = array();

        foreach($oneLevelLower as $oll)

            $lastEl = $oll[$n-2];
            $found = false;
            foreach($base as  $key => $b)
                if($b == $lastEl)
                    $found = true;
                    continue;
                    //last element found

                
                if($found == true)
                        //add to combinations with last element
                        if($key < $baselen)

                            $tmp = $oll;
                            $newCombination = array_slice($tmp,0);
                            $newCombination[]=$b;
                            $newCombs[] = array_slice($newCombination,0);
                        

                
            

        

    

    return $newCombs;



我一直在玩($b == $lastEl) 行,没有运气

================

我已经查看过的问题与导致内存不足错误的 OR 不同!:

How can I get all permutations in PHP without sequential duplicates? Permutations - all possible sets of numbers Combinations, Dispositions and Permutations in PHP PHP array combinations Get all permutations of a PHP array? PHP: How to get all possible combinations of 1D array? Select only unique array values from this array Get all permutations of a PHP array? PHP: How to get all possible combinations of 1D array? Select only unique array values from this array How can I get all permutations in PHP without sequential duplicates? Algorithm to return all combinations of k elements from n Find combination(s) sum of element(s) in array whose sum equal to a given number Combinations, Dispositions and Permutations in PHP PHP array combinations Php recursion to get all possibilities of strings How to return permutations of an array in PHP? Permutations - all possible sets of numbers Subset-sum problem in PHP with mysql Find unique combinations of values from arrays filtering out any duplicate pairs Finding all the unique permutations of a string without generating duplicates Generate all unique permutations Subset sum for exactly k integers?

我已经尝试了其中一些算法,其中包含 12 个项目,但最终内存不足。然而,我目前使用的算法并没有给我一个内存不足的错误....但是..我需要那些重复的!

【问题讨论】:

请给出输入数据和预期输出的正确示例。 var_dump() 格式适合 我终于在 PHP 中找到了一个递归的东西——请看我的回答... 【参考方案1】:

如果您不介意使用几个全局变量,您可以在 PHP 中执行此操作(翻译自 javascript 中的 version):

<?PHP
$result = array(); 
$combination = array();

function combinations(array $myArray, $choose) 
  global $result, $combination;

  $n = count($myArray);

  function inner ($start, $choose_, $arr, $n) 
    global $result, $combination;

    if ($choose_ == 0) array_push($result,$combination);
    else for ($i = $start; $i <= $n - $choose_; ++$i) 
           array_push($combination, $arr[$i]);
           inner($i + 1, $choose_ - 1, $arr, $n);
           array_pop($combination);
         
  
  inner(0, $choose, $myArray, $n);
  return $result;


print_r(combinations(array(20,20,22,24), 3));
?>

输出:

Array ( [0] => Array ( [0] => 20 
                       [1] => 20 
                       [2] => 22 ) 
        [1] => Array ( [0] => 20 
                       [1] => 20 
                       [2] => 24 ) 
        [2] => Array ( [0] => 20 
                       [1] => 22 
                       [2] => 24 ) 
        [3] => Array ( [0] => 20 
                       [1] => 22 
                       [2] => 24 ) ) 

【讨论】:

这里还有一个梨包:pear.php.net/package/Math_Combinatorics【参考方案2】:

pear 包 Math_Combinatorics 使这类问题变得相当容易。它需要的代码相对较少,简单明了,而且很容易阅读。

$ cat code/php/test.php
<?php
$input = array(20, 20, 22, 24);

require_once 'Math/Combinatorics.php';

$c = new Math_Combinatorics;
$combinations = $c->combinations($input, 3);
for ($i = 0; $i < count($combinations); $i++) 
  $vals = array_values($combinations[$i]);
  $s = implode($vals, ", ");
  print $s . "\n";

?>

$ php code/php/test.php
20, 20, 22
20, 20, 24
20, 22, 24
20, 22, 24

如果我必须把它打包成一个函数,我会做这样的事情。

function combinations($arr, $num_at_a_time) 

    include_once 'Math/Combinatorics.php';

    if (count($arr) < $num_at_a_time) 
        $arr_count = count($arr);
        trigger_error(
            "Cannot take $arr_count elements $num_at_a_time " 
            ."at a time.", E_USER_ERROR
        );
    

    $c = new Math_Combinatorics;
    $combinations = $c->combinations($arr, $num_at_a_time);

    $return = array();
    for ($i = 0; $i < count($combinations); $i++) 
        $values = array_values($combinations[$i]);
        $return[$i] = $values;
    
    return $return;

这将返回一个数组数组。获取文本。 . .

<?php
  include_once('combinations.php');

  $input = array(20, 20, 22, 24);
  $output = combinations($input, 3);

  foreach ($output as $row) 
      print implode($row, ", ").PHP_EOL;
  
?>
20, 20, 22
20, 20, 24
20, 22, 24
20, 22, 24

【讨论】:

为什么要重新发明***?这可能是这里最好的答案,我已经下载了梨类并将其包含在我的项目中......谢谢【参考方案3】:

为什么不只使用二进制?至少那么它简单且很容易理解每​​一行代码的作用是这样的吗?这是我在一个项目中为自己编写的一个函数,我认为它非常简洁!

function search_get_combos($array)
$bits = count($array); //bits of binary number equal to number of words in query;
//Convert decimal number to binary with set number of bits, and split into array
$dec = 1;
$binary = str_split(str_pad(decbin($dec), $bits, '0', STR_PAD_LEFT));
while($dec < pow(2, $bits)) 
    //Each 'word' is linked to a bit of the binary number.
    //Whenever the bit is '1' its added to the current term.
    $curterm = "";
    $i = 0;
    while($i < ($bits))
        if($binary[$i] == 1) 
            $curterm[] = $array[$i]." ";
        
        $i++;
    
    $terms[] = $curterm;
    //Count up by 1
    $dec++;
    $binary = str_split(str_pad(decbin($dec), $bits, '0', STR_PAD_LEFT));

return $terms;
 

对于您的示例,此输出:

Array
(
    [0] => Array
        (
            [0] => 24 
        )
    [1] => Array
        (
            [0] => 22 
        )
    [2] => Array
        (
            [0] => 22 
            [1] => 24 
        )
    [3] => Array
        (
            [0] => 20 
        )
    [4] => Array
        (
            [0] => 20 
            [1] => 24 
        )
    [5] => Array
        (
            [0] => 20 
            [1] => 22 
        )
    [6] => Array
        (
            [0] => 20 
            [1] => 22 
            [2] => 24 
        )
    [7] => Array
        (
            [0] => 20 
        )
    [8] => Array
        (
            [0] => 20 
            [1] => 24 
        )
    [9] => Array
        (
            [0] => 20 
            [1] => 22 
        )
    [10] => Array
        (
            [0] => 20 
            [1] => 22 
            [2] => 24 
        )
    [11] => Array
        (
            [0] => 20 
            [1] => 20 
        )
    [12] => Array
        (
            [0] => 20 
            [1] => 20 
            [2] => 24 
        )
    [13] => Array
        (
            [0] => 20 
            [1] => 20 
            [2] => 22 
        )
    [14] => Array
        (
            [0] => 20 
            [1] => 20 
            [2] => 22 
            [3] => 24 
        )
)

【讨论】:

【参考方案4】:

想法很简单。假设你知道如何排列,那么如果你将这些排列保存在一个集合中,它就会变成一个组合。按定义设置会处理重复值。 Set 或 HashSet 的 Php 等价物是 SplObjectStorage,而 ArrayList 是 Array。重写应该不难。我有一个 Java 实现:

public static HashSet<ArrayList<Integer>> permuteWithoutDuplicate(ArrayList<Integer> input)
          if(input.size()==1)
              HashSet<ArrayList<Integer>> b=new HashSet<ArrayList<Integer>>();
              b.add(input);
              return b;
          
          HashSet<ArrayList<Integer>>ret= new HashSet<ArrayList<Integer>>();
          int len=input.size();
          for(int i=0;i<len;i++)
              Integer a = input.remove(i);
              HashSet<ArrayList<Integer>>temp=permuteWithoutDuplicate(new ArrayList<Integer>(input));
              for(ArrayList<Integer> t:temp)
                  t.add(a);
              ret.addAll(temp);
              input.add(i, a);
          
          return ret;
      

【讨论】:

【参考方案5】:

遇到了同样的问题,找到了一个不同的、按位更快的解决方案:

function bitprint($u) 
    $s = array();
    for ($n=0; $u; $n++, $u >>= 1)
        if ($u&1)
            $s [] = $n;
        
    
    return $s;

function bitcount($u) 
    for ($n=0; $u; $n++, $u = $u&($u-1));
    return $n;

function comb($c,$n) 
    $s = array();
    for ($u=0; $u<1<<$n; $u++)
        if (bitcount($u) == $c)
            $s [] = bitprint($u);
        
    
    return $s;

这个生成从 0 到 n-1 的所有大小为 m 的整数组合,例如 m = 2, n = 3 并调用 comb(2, 3) 将产生:

0 1
0 2
1 2

它为您提供索引位置,因此很容易通过索引指向数组元素。

编辑: 输入 comb(30, 5) 失败。不知道为什么,有人知道吗?

【讨论】:

你说得对,这是从 javascript 翻译过来的,甚至 javascript 代码也会因为相同的输入而失败。 它有效,但 comb(30,5) 无效。我认为是因为输入错误,30太高了。【参考方案6】:

使用 strrev 和 for/foreach 循环清理了 Adi Bradfield 的建议,并且只得到独特的结果。

function search_get_combos($array = array()) 
sort($array);
$terms = array();

for ($dec = 1; $dec < pow(2, count($array)); $dec++) 
    $curterm = array();
    foreach (str_split(strrev(decbin($dec))) as $i => $bit) 
        if ($bit) 
            $curterm[] = $array[$i];
        
    
    if (!in_array($curterm, $terms)) 
        $terms[] = $curterm;
    


return $terms;

【讨论】:

以上是关于PHP查找数组的所有(有点)唯一组合的主要内容,如果未能解决你的问题,请参考以下文章

PHP 查找数组的所有元素组合

从字符串数组创建唯一组合数组

如何在 PHP 中生成多个数组中的所有项目组合

查找并打印总和为 100 的每个唯一组合,并返回 1 到 100 之间数字的所有此类组合的计数 [重复]

快速查找字符串数组的所有组合

查找 JavaScript 数组值的所有组合(笛卡尔积)