【问题标题】:Combinations, Dispositions and Permutations in PHPPHP 中的组合、配置和排列
【发布时间】:2010-12-13 08:53:13
【问题描述】:

在 PHP 中生成数组的所有组合、配置和排列的最有效方法是什么?

【问题讨论】:

    标签: php algorithm arrays math combinatorics


    【解决方案1】:

    这是获取所有排列的代码:

    http://php.net/manual/en/function.shuffle.php#90615

    用代码得到幂集,排列是最大长度的排列,幂集应该是所有的组合。我不知道什么是性格,所以如果你能解释一下,那会有所帮助。

    【讨论】:

    • 这个答案已有 10 多年的历史了,在现代 PHP 中,这不是你应该做的事情,尤其是这种内存和 CPU 密集型算法。请参阅下面的生成器答案。
    【解决方案2】:

    你可以使用这个类:http://pear.php.net/package/Math_Combinatorics

    并像这样使用它:

    $combinatorics = new Math_Combinatorics;
    
    $words_arr = array(
        'one'   => 'a',
        'two'   => 'b',
        'three' => 'c',
        'four'  => 'd',
        );
    
    for ($i=count($words_arr)-1;$i>=1;$i--) {
        echo '<br><br>' . $i . ':<br>';
        $combinations_arr = $combinatorics->combinations($words_arr, $i);
        foreach ($combinations_arr as $combinations_arr_item) {
            echo implode(', ', $combinations_arr_item) . '<br>';
        }
    }
    

    【讨论】:

    • PEAR 在 PHP 7.4 中已被弃用,将在 PHP 8 中完全删除。
    【解决方案3】:

    我想建议我的 CombinationsGenerator 解决方案,它生成数组项的组合。

    仅限于所有组合都是完整的长度,并且不重复任何项目。但我相信实施不会太难。

    class CombinationsGenerator
    {
        public function generate(array $list): \Generator
        {
            if (count($list) > 2) {
                for ($i = 0; $i < count($list); $i++) {
                    $listCopy = $list;
    
                    $entry = array_splice($listCopy, $i, 1);
                    foreach ($this->generate($listCopy) as $combination) {
                        yield array_merge($entry, $combination);
                    }
                }
            } elseif (count($list) > 0) {
                yield $list;
    
                if (count($list) > 1) {
                    yield array_reverse($list);
                }
            }
        }
    }
    
    $generator = new \CombinationsGenerator();
    
    foreach ($generator->generate(['A', 'B', 'C', 'D']) as $combination) {
        var_dump($combination);
    }
    

    它采用 PHP7 风格,使用 \Generator,因为我相信这样做是有充分理由的。

    【讨论】:

      【解决方案4】:
      /* Combinations */
      function nCr($n, $r)
      {
        if ($r > $n)
        {
          return NaN;
        }
        if (($n - $r) < $r)
        {
          return nCr($n, ($n - $r));
        }
        $return = 1;
        for ($i = 0; $i < $r; $i++)
        {
          $return *= ($n - $i) / ($i +1);
        }
        return $return;
      }
      
      /* Permutations */
      function nPr($n, $r)
      {
        if ($r > $n)
        {
          return NaN;
        }
        if ($r)
        {
          return $n * (nPr($n -1, $r -1));
        }
        else
        {
          return 1;
        }
      }
      

      【讨论】:

        【解决方案5】:

        我不得不修改@hejdav 的答案,使其包含部分组合,以便完全提供所有结果。

        我在互联网上搜索了这个解决方案,截至 2019 年 6 月,我相信这是唯一一个真正列出所有可能的、非重复的可能性的可公开访问的答案(任何地方)。

        class CombinationsGenerator
        {
            /**
             * Taken from https://stackoverflow.com/a/39447347/430062.
             * 
             * @param array $list
             * @return \Generator
             */
            public function generate(array $list): \Generator
            {
                // Generate even partial combinations.
                $list = array_values($list);
                $listCount = count($list);
                for ($a = 0; $a < $listCount; ++$a) {
                    yield [$list[$a]];
                }
        
                if ($listCount > 2) {
                    for ($i = 0; $i < count($list); $i++) {
                        $listCopy = $list;
        
                        $entry = array_splice($listCopy, $i, 1);
                        foreach ($this->generate($listCopy) as $combination) {
                            yield array_merge($entry, $combination);
                        }
                    }
                } elseif (count($list) > 0) {
                    yield $list;
        
                    if (count($list) > 1) {
                        yield array_reverse($list);
                    }
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2020-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-28
          • 1970-01-01
          • 1970-01-01
          • 2017-03-13
          相关资源
          最近更新 更多