以特定间隔合并阵列

时间:2019-04-09 10:12:21

标签: php arrays

我要合并两个数组,以便首先插入数组A的前X个元素,然后一次又一次插入数组B的Y个元素,直到新数组包含两个数组中的所有元素。如果数组中的元素数量没有加起来,则应从数组的开头重新开始合并。

类似这样的东西:

<?php
$arrA = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
$arrB = [1, 2, 3, 4];

# Print 2A 1B 2A 1B etc until no element is missing from the new array - as soon as new array contains all elements break
array_merge_interval($arrA, $arrB, 2, 1);

['A', 'B', 1, 'C', 'D', 2, 'E', 'F', 3, 'G', 'H', 4]

# Print 2B 1A 2B 1A etc until no element is missing from the new array - as soon as new array contains all elements break
array_merge_interval($arrB, $arrA, 2, 1);

[1, 2, 'A', 3, 4, 'B', 1, 2, 'C', 3, 4, 'D', 1, 2, 'E', 3, 4, 'F', 1, 2, 'G', 3, 4, 'H']

# Print 6B 0A etc until no element is missing from the new array - as soon as new array contains all elements break
array_merge_interval($arrB, $arrA, 6, 0);

[1, 2, 3, 4]

# Print 20A 3B etc  until no element is missing from the new array - as soon as new array contains all elements break
array_merge_interval($arrA, $arrB, 20, 3);

['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 1, 2, 3, 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 4]

我已经尝试过使用嵌套的for(每个)循环进行许多复杂的解决方案,但是我非常不满意(并且还没有完成),所以我希望有人可以使用一些未知的数组函数想出一些聪明的东西?

3 个答案:

答案 0 :(得分:3)

您可以使用此功能使其完全适合您的情况,

function array_merge_interval($a, $b, $aLength, $bLength)
{
    $i    = 0;
    $k    = 0;
    $temp = [];
    $flag = '';
    if (!$bLength || !$aLength) {
        return ((!$bLength && !$aLength) ? [] : (!$bLength ? $a : $b));
    }
    while (true) {
        $j = 0;
        while ($j != $aLength) {
            $j++;
            if ($i < count($a)) {
                $temp[] = $a[$i];
                $i++;
            } else {
                $i      = 0;
                $temp[] = $a[$i];
                $i++;
                continue;
            }
        }
        $l = 0;
        while ($l < $bLength) {
            if ($k < count($b)) {
                $temp[] = $b[$k];
                $k++;
            }
            $l++;
        }
        if ($bLength == 0 || $flag == 'warning') {
            break;
        }
        if ($b[$k] == $b[count($b) - 1]) {
            $flag = 'warning';
        }
    }
    return $temp;
}

在演示中,我显示了您期望的所有输出。
根据我的观察,{$ {1}}元素会重复自身直到$a,直到$ b元素不会完成为止。

Demo

答案 1 :(得分:2)

您可以使用这对功能:

function array_get_chunk($a, $size, &$i, &$leftOver) {
    do {
        $result[] = $a[$i % count($a)];
        $i++;
        if ($i <= count($a)) $leftOver--;
    } while ($i % $size && $leftOver);
    return $result;
}

function array_merge_interval($a, $b, $sizeA, $sizeB) {
    if (!$sizeA && !$sizeB) return [];
    if (!$sizeA) return $b;
    if (!$sizeB) return $a;

    $i = $j = 0;
    $result = [];
    $leftOver = count($a) + count($b);
    do {
        array_push($result, ...array_get_chunk($a, $sizeA, $i, $leftOver));
        if ($leftOver) array_push($result, ...array_get_chunk($b, $sizeB, $j, $leftOver));
    } while ($leftOver);
    return $result;
}

array_get_chunk函数是一个辅助函数。它需要一个数组,块大小,块应开始的偏移量以及允许访问的未访问元素的最大数量。

最后两个参数由引用传递,因为它们由函数更新。偏移量$i将增加并且可能会超出数组的大小,因此将应用模(%)将其映射到有效的数组索引。仅当该索引确实在范围内(不取模)时,我们才认为它是数组元素的 first 访问,因此只有$leftOver减少。

一旦生成了完整的块,或者$leftOver变量达到0,我们就会将该块返回给调用方。

主要功能array_merge_interval首先检查一些简单的边界情况,其中一个或两个大小均为零。然后,将$leftOver变量设置为两个数组中的元素总数。这样可以确保在至少收集完所有元素一次后,该过程将停止。

该循环为两个数组中的每个数组调用helper函数,并使用array_push(和splash运算符)将返回的块添加到最终结果中。这一直持续到$leftOver达到0。

答案 2 :(得分:1)

在ArrayIterator帮助下看起来会更好:

<?php
$arrA = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
$arrB = [1, 2, 3, 4];

var_dump(array_merge_interval($arrA, $arrB, 2, 1) == ['A', 'B', 1, 'C', 'D', 2, 'E', 'F', 3, 'G', 'H', 4]);
var_dump(array_merge_interval($arrB, $arrA, 2, 1) == [1, 2, 'A', 3, 4, 'B', 1, 2, 'C', 3, 4, 'D', 1, 2, 'E', 3, 4, 'F', 1, 2, 'G', 3, 4, 'H']);
var_dump(array_merge_interval($arrB, $arrA, 6, 0) == [1, 2, 3, 4]);
var_dump(array_merge_interval($arrA, $arrB, 20, 3) == ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 1, 2, 3, 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 4]);

function array_merge_interval(array $arrA, array $arrB, int $sizeA, int $sizeB): array
{
    $res = [];

    $itA = new ArrayIterator($arrA);
    $itB = new ArrayIterator($arrB);
    $stopA = $sizeA <= 0;
    $stopB = $sizeB <= 0;

    while (!($stopA && $stopB)) {
        $stopA = addItem($sizeA, $res, $itA, $stopB);
        $stopB = addItem($sizeB, $res, $itB, $stopA);
    }

    return $res;
}

function addItem(int $size, array &$res, ArrayIterator $iterator, bool $stop): bool
{
    if ($size <= 0) {
        return true;
    }

    $flag = false;
    for ($i = 0; $i < $size; $i++) {
        $res[] = $iterator->current();
        $iterator->next();
        if (!$iterator->current()) {
            $iterator->rewind();

            if ($stop) {
                return true;
            }

            $flag = true;
        }
    }

    return $flag;
}

Demo