每个人都知道在给定的n大小算法数组中找到r元素的可能组合,但我还需要更进一步。
我有一系列物品。这些项是数组,有id,name,group_id bla bla bla。
我必须使用不同的group_id计算可能的组合。如果Items具有相同的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
],
.
.
.
.
.
]
感谢。
答案 0 :(得分:0)
我不知道你是否想要一个奇特的解决方案,但这可能是一个非常简单的解决方案,基本上,你所做的是在不同的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
==组数现在没有太多解释,如果您需要解释,请发表评论。 但是这段代码可能会有一些小错误,但是没有对它进行测试。
构建一个数组($grouped
),其中每个元素都是一个包含具有相同group_id的项的数组,所以基本上
$grouped = [];
foreach($array as $item) {
if(empty($grouped[$item['group_id']]) $grouped[$item['group_id']] = [];
$grouped[$item['group_id']][] = $item;
}
递归地取每组的一个元素:
$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
个元素的组合,你可以用
// 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));
答案 1 :(得分:0)
最后我再次找到了我的解决方案:)
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());
}
}