【问题标题】:Find possible combinations of r elements in given array of size n with group在给定的大小为 n 的数组中找到 r 个元素与组的可能组合
【发布时间】:2017-10-05 08:49:03
【问题描述】:

每个人都知道在给定大小为 n 的数组中找到 r 个元素的可能组合,但我需要更进一步。

我有一系列项目。这些项目是数组,有id、name、group_id bla bla bla。

我必须计算不同 group_id 的可能组合。如果 Item 具有相同的 group_id,则它们不能创建组合。

这是我计算所有可能组合的函数;

private function calculateComb(array $temp, int $start, int $end, int $index, int $size)
    {
        try {
            if ($index === $size) {
                $this->groups[$size]['combinations'][] = $temp;
                return;
            }
            for ($i = $start; $i < $end; $i++) {
                $temp[$index] = $this->combinationItems[$i];
                $this->calculateComb($temp, $i + 1, $end, $index + 1, $size);
            }
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
    }

我尝试创建一个新函数来计算与 group_id 的可能组合;

private function calculateCombinations(array $temp, int $start, int $end, int $size, int $index, array &$groupIds)
    {
        try {
            if ($index === $size) {
                $this->groups[$size]['combinations'][] = $temp;
                unset($groupIds[$index]);
                return;
            }
            for ($i = $start; $i < $end; $i++) {
                if (in_array($this->combinationItems[$i]['group_id'], $groupIds)) {
                    $this->calculateCombinations($temp, $i + 1, $end, $size, $index, $groupIds);
                } else {
                    $temp[$index] = $this->combinationItems[$i];
                    $groupIds[$index] = $this->combinationItems[$i]['group_id'];

                    $this->calculateCombinations($temp, $i + 1, $end, $size, $index + 1, $groupIds);
                }
            }
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
    }

但这不起作用。你有什么想法吗?

数组示例;

[
    [
        'id': 1,
        'name': 'Test',
        'group_id': 1
    ], [
        'id': 2,
        'name': 'Test2',
        'group_id': 1
    ], [
        'id': 3,
        'name': 'Test3',
        'group_id': 2
    ],
    .
    .
    .
    .
    .
]

谢谢。

【问题讨论】:

    标签: php


    【解决方案1】:

    2 元素组合的解决方案

    我不知道您是否想要一个花哨的解决方案,但这可能是一个非常简单的解决方案,本质上,您所做的是加入不同的 group_id。下面本质上是一个嵌套循环连接。如果您想要/需要更高效/更快,可能会有不同的连接算法更适合,但我认为嵌套循环连接在这种情况下非常有效。

    嵌套循环连接:

    $output = [];
    foreach($array as $left) {
        foreach($array as $right) {
            if($left['group_id'] != $right['group_id']) { // <-- join condition
                 // create output, you probably want something else here...
                 $output[] = ['left' => $left, 'right' => $right];
            }
        }
    }
    

    这将创建所有组合:如果 (a,b) 是一个组合,则 (b,a) 也是一个组合。 如果这不是您想要的,您也可以包含密钥:

    // ...
    foreach($array as $lid => $left) { // <-- notice the l(eft) id
        foreach($array as $rid => $right) { // <-- notice r(ight) id
            if($lid < $rid && $left['group_id'] != $right['group_id']) {
               // ^^^^^^^ this ensures only one of the two combination will be joined
            }
        }
    }
    

    (编辑...)

    k-元素组合,其中k == 组数

    暂时没有太多解释,如果您需要解释,请评论。 这段代码可能有一些小错误,但没有测试它。

    1. 构建一个数组($grouped),其中每个元素都是一个数组,其中包含具有相同 group_id 的项目,所以本质上是

      $grouped = [];
      foreach($array as $item) {
          if(empty($grouped[$item['group_id']]) $grouped[$item['group_id']] = [];
          $grouped[$item['group_id']][] = $item; 
      }
      
    2. 递归地从每个组中取出一个元素:

      $grouped = array_values($grouped); // this simplifies keys
      
      function get_combinations($grouped, $i) {
          // in the k-th group, return all elements
          if(count($grouped)-1 == $i) {
              $ret = [];
              foreach($grouped[$i] as $item) {
                  $ret[] = [$item];
              }
              return $ret;
          }
      
          // in the $i-th group ($i < k), build combinations of each element
          // in i-th group with every combination given from sub-call
          $subcombinations = get_combinations($grouped, $i+1);
          $result = []; // <--- REFERENCED LINE ...
          foreach($grouped[$i] as $item) {
              foreach($subcombinations as $comb) {
                  $result[] = array_merge([$item], $comb);
              }
          }
          // return new combinations
          return $result;
      }
      
      $combinations = get_combinations($grouped, 0);
      

    现在,如果包含许多大型组,这对于非常大的数组可能非常低效。

    至少包含一项的所有组合

    如果您还想计算具有少于 k 元素的组合,您可以将引用的行(参见上面代码中的 REFERENCED LINE)替换为

    // add combinations without current group to result
    // also add single-element combinations where element is from current group
    $result = array_merge($subcombinations, get_combinations([$grouped[$i]],0));
    

    【讨论】:

    • 是的,这是一个很好的解决方案,但它有一个问题,它只适用于 2 种尺寸组合。如果我想找到 3 种或更多尺寸组合,它就行不通。谢谢。
    • 显然我误解了你的问题描述;o)
    • 非常感谢,但正如您所说,对于非常大的数组来说效率非常低,我必须计算非常大的数组的可能组合。似乎找到所有可能的组合然后检查这些组合会更有效:)
    • 值得怀疑,但我对最后的解决方案感兴趣,如果你愿意提供的话。当然,除非你使用一些捷径,比如只使用 id 而不是项目本身(这也是你可以用我的解决方案做的事情)并且只在需要时将它们扩展为项目。
    • 找到了一种组合组合的方法:)
    【解决方案2】:

    我终于又找到了解决办法:)

    private function calculateCombinations(array $temp, int $start, int $end, int $size, int $index, array &$groupIds)
        {
            try {
                if ($index === $size) {
                    $this->groups[$size]['combinations'][] = $temp;
                    $groupIds = [];
                    return;
                }
                for ($i = $start; $i < $end; $i++) {
                    if (in_array($this->combinationItems[$i]['group_id'], $groupIds)) {
                        continue;
                    } else {
                        $temp[$index] = $this->combinationItems[$i];
                        $groupIds[$index] = $this->combinationItems[$i]['group_id'];
    
                        $this->calculateCombinations($temp, $i + 1, $end, $size, $index + 1, $groupIds);
                    }
                }
            } catch (\Exception $e) {
                throw new \Exception($e->getMessage());
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-23
      • 2020-04-17
      • 1970-01-01
      • 2018-04-24
      • 1970-01-01
      • 2017-12-10
      • 2016-03-12
      • 1970-01-01
      相关资源
      最近更新 更多