【问题标题】:Better method of finding every possible combination of the partitioned sets找到分区集的每个可能组合的更好方法
【发布时间】:2012-04-21 04:54:44
【问题描述】:

我需要找到 N 组 X 长度且不重复且按特定顺序的所有可能组合,例如

input:  [["A"], ["B"], ["C"]]
output: [["A","B","C"],["A","B"],["A","C"],["B","C"],["A"],["B"],["C"]]

规则:

  • 分区的数量或大小不固定。
  • 每个组合中的每个分区只有一个成员。
  • 成员越多的组合优先级越高。
  • 输入中较早的成员的优先级高于后来的成员。

另一个更大集合的例子:

input:  [["A","B"],["C","D","E"],["F"]]
output: [["A","C","F"],["A","D","F"],["A","E","F"],["B","C","F"],["B","D","F"],["B","E","F"],["A","C"],["A","D"],["A","E"],["B","C"],["B","D"],["B","E"],["A","F"],["B","F"],["C","F"],["D","F"],["E","F"],["A"],["B"],["C"],["D"],["E"],["F"]]

通过将幂集函数的输出与笛卡尔积函数相结合,我设法获得了我想要的输出,但生成的代码不是很简洁或漂亮。我想知道这是否可以通过递归更好地完成?

这是我已经拥有的:

$test = json_decode('[["A"]]');
$test1 = json_decode('[["A"], ["B"], ["C"]]');
$test2 = json_decode('[["A", "B"], ["C", "D", "E"], ["F"]]');

/**
 * Returns a power set of the input array.
 */                   
function power_set($in, $minLength = 1) {
  $count = count($in);
  $members = pow(2,$count);
  $return = array();

  for ($i = 0; $i < $members; $i++) {
    $b = sprintf("%0".$count."b",$i);
    $out = array();

    for ($j = 0; $j < $count; $j++) {
      if ($b[$j] == '1') {
        $out[] = $in[$j];
      }
    }
    if (count($out) >= $minLength) {
      $return[] = $out;
    }
  }

  return $return;
}

/**
 * Returns the cartesian product of the input arrays.
 */
function array_cartesian() {
  $_ = func_get_args();

  if(count($_) == 0) {
    return array(array());
  }

  $a = array_shift($_);
  $c = call_user_func_array(__FUNCTION__, $_);
  $r = array();

  foreach($a as $v) {
    foreach($c as $p) {
      $r[] = array_merge(array($v), $p);
    }
  }

  return $r;
}

/**
 * Used with usort() to sort arrays by length, desc.
 * If two arrays are the same length, then a sum of 
 * their keys is taken, with lower values coming first.
 */
function arraySizeDesc($a, $b) {
  if(count($a) === count($b)) {
    if(array_sum($a) === array_sum($b)) {
      return 0;
    }

    return (array_sum($a) > array_sum($b)) ? 1 : -1;
  }

  return (count($a) < count($b)) ? 1 : -1;
}

/**
 * Calculates a powerset of the input array and then uses
 * this to generate cartesian products of each combination
 * until all possible combinations are aquired.
 */
function combinations($in) {
 $out = array();
 $powerSet = power_set(array_keys($in));
 usort($powerSet, 'arraySizeDesc');

 foreach($powerSet as $combination) {
   if(count($combination) < 2) {
     foreach($in[$combination[0]] as $value) {
       $out[] = array($value);
     }
   } else {
     $sets = array();

     foreach($combination as $setId) {
       $sets[] = $in[$setId];
     }

     $out = array_merge($out, call_user_func_array('array_cartesian', $sets));
   }
 }

 return $out;
}

echo "input: ".json_encode($test2);
echo "<br />output: ".json_encode(combinations($test2));

我意识到输出的大小可以非常迅速地增长,但输入通常应该只包含 1-5 个 1-50 个成员的集合,因此不需要处理大量集合。​​

【问题讨论】:

    标签: php algorithm recursion set cartesian


    【解决方案1】:

    基本上,您的方法是生成输入的幂集,然后对其进行后处理以达到您想要的输出。

    人们可以通过尝试直接解决它来以不同的方式处理它。我想到的一种解决方案如下。

    给定输入 A = [ A1, ...],假设问题已经解决了 A \ A1。将此解决方案称为 S'。我们如何将 S' 转换为整个 A 的解 S?这本质上是通过制作 S' 的两个副本。我们将 A1 的元素分配到第一个副本中。我们称新序列为 S''。因此,A 的解变成了 S'' 和 S' 的简单串联。

    算法,

    Input: A = [ A1, A2, ..., An]

    组合(A,i,n):

    1. 如果 n
    2. 返回[]
    3. 如果 n == i
    4. 返回单例(Ai
    5. S' = combine(A, i + 1, n)
    6. S'' = [a, S'],对于 Ai 中的每个 a
    7. 返回 [S'', S']

    函数singletons 返回输入集的单元素子集族。因此,如果它接受输入 [1, 2, 3],它将返回 [[1], [2], [3]]。

    如果你忽略一些松散的序列连接在这里和那里的用法,那么这个方法应该很清楚......

    祝你好运!

    【讨论】:

      【解决方案2】:

      试试

      $test = array ();
      $test [0] = json_decode ( '[["A"]]', true );
      $test [1] = json_decode ( '[["A"], ["B"], ["C"]]', true );
      $test [2] = json_decode ( '[["A", "B"], ["C", "D", "E"], ["F"]]', true );
      
      
      echo "<pre>" ;
      $set = array ();
      getSet ( $test, $set );
      $set = array_values(array_unique($set));
      $return = powerSet($set,1,3);
      print_r ($return);
      

      输出

      Array
      (
          [0] => Array
              (
                  [0] => F
              )
      
          [1] => Array
              (
                  [0] => E
              )
      
          [2] => Array
              (
                  [0] => E
                  [1] => F
              )
      
          [3] => Array
              (
                  [0] => D
              )
      
          [4] => Array
              (
                  [0] => D
                  [1] => F
              )
      
          [5] => Array
              (
                  [0] => D
                  [1] => E
              )
      
          [6] => Array
              (
                  [0] => D
                  [1] => E
                  [2] => F
              )
      
          [7] => Array
              (
                  [0] => C
              )
      
          [8] => Array
              (
                  [0] => C
                  [1] => F
              )
      
          [9] => Array
              (
                  [0] => C
                  [1] => E
              )
      
          [10] => Array
              (
                  [0] => C
                  [1] => E
                  [2] => F
              )
      
          [11] => Array
              (
                  [0] => C
                  [1] => D
              )
      
          [12] => Array
              (
                  [0] => C
                  [1] => D
                  [2] => F
              )
      
          [13] => Array
              (
                  [0] => C
                  [1] => D
                  [2] => E
              )
      
          [14] => Array
              (
                  [0] => B
              )
      
          [15] => Array
              (
                  [0] => B
                  [1] => F
              )
      
          [16] => Array
              (
                  [0] => B
                  [1] => E
              )
      
          [17] => Array
              (
                  [0] => B
                  [1] => E
                  [2] => F
              )
      
          [18] => Array
              (
                  [0] => B
                  [1] => D
              )
      
          [19] => Array
              (
                  [0] => B
                  [1] => D
                  [2] => F
              )
      
          [20] => Array
              (
                  [0] => B
                  [1] => D
                  [2] => E
              )
      
          [21] => Array
              (
                  [0] => B
                  [1] => C
              )
      
          [22] => Array
              (
                  [0] => B
                  [1] => C
                  [2] => F
              )
      
          [23] => Array
              (
                  [0] => B
                  [1] => C
                  [2] => E
              )
      
          [24] => Array
              (
                  [0] => B
                  [1] => C
                  [2] => D
              )
      
          [25] => Array
              (
                  [0] => A
              )
      
          [26] => Array
              (
                  [0] => A
                  [1] => F
              )
      
          [27] => Array
              (
                  [0] => A
                  [1] => E
              )
      
          [28] => Array
              (
                  [0] => A
                  [1] => E
                  [2] => F
              )
      
          [29] => Array
              (
                  [0] => A
                  [1] => D
              )
      
          [30] => Array
              (
                  [0] => A
                  [1] => D
                  [2] => F
              )
      
          [31] => Array
              (
                  [0] => A
                  [1] => D
                  [2] => E
              )
      
          [32] => Array
              (
                  [0] => A
                  [1] => C
              )
      
          [33] => Array
              (
                  [0] => A
                  [1] => C
                  [2] => F
              )
      
          [34] => Array
              (
                  [0] => A
                  [1] => C
                  [2] => E
              )
      
          [35] => Array
              (
                  [0] => A
                  [1] => C
                  [2] => D
              )
      
          [36] => Array
              (
                  [0] => A
                  [1] => B
              )
      
          [37] => Array
              (
                  [0] => A
                  [1] => B
                  [2] => F
              )
      
          [38] => Array
              (
                  [0] => A
                  [1] => B
                  [2] => E
              )
      
          [39] => Array
              (
                  [0] => A
                  [1] => B
                  [2] => D
              )
      
          [40] => Array
              (
                  [0] => A
                  [1] => B
                  [2] => C
              )
      
      )
      

      使用的功能

      function powerSet($in, $minLength = 1, $max = 10) {
          $count = count ( $in );
          $members = pow ( 2, $count );
          $return = array ();
          for($i = 0; $i < $members; $i ++) {
              $b = sprintf ( "%0" . $count . "b", $i );
              $out = array ();
              for($j = 0; $j < $count; $j ++) {
                  if ($b {$j} == '1')
                      $out [] = $in [$j];
              }
              if (count ( $out ) >= $minLength && count ( $out ) <= $max) {
                  $return [] = $out;
              }
      
          }
          return $return;
      }
      
      function getSet($array, &$vals) {
          foreach ( $array as $key => $value ) {
      
              if (is_array ( $value )) {
      
                  getSet ( $value, $vals );
      
              } else {
      
                  $vals [] = $value;
              }
          }
      
          return $vals;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-28
        • 1970-01-01
        • 2021-03-15
        • 2021-06-11
        • 2017-08-27
        • 1970-01-01
        相关资源
        最近更新 更多