qwertymk
qwertymk

Reputation: 35304

Merge two flat indexed arrays of equal size so that values are pushed into the result in an alternating fashion

Suppose I have two arrays:

$a1 = array(0, 1, 2);
$a2 = array(3, 4, 5);

I want to be able to do a merge technique that alternates the array values and not just concatenate them. I want this result:

array(0, 3, 1, 4, 2, 5);

Is there a native way to do this as performance is an issue here since I need to do this thousands of times

Please note, I know I can do it like this:

for (var $i = 0; $i < count($a1); $i++) {
    newArray[] = $a1[$i];
    newArray[] = $b1[$i];
}

I'm looking for a built in way if there is a faster one.

Upvotes: 6

Views: 1489

Answers (2)

mickmackusa
mickmackusa

Reputation: 48031

Since you are "zippering" two indexed arrays, you can "transpose and flatten". I expect that this will not be quite as fast as using a for() or foreach(), but on small input arrays, there will be no noticeable drag on performance. In other words, when coding style or minimal declared variables is sought, then the following technique should be considered.

Code: (Demo)

$a1 = [0, 1, 2];
$a2 = [3, 4, 5];

var_export(
    array_merge(...array_map(null, $a1, $a2))
);

Output:

array (
  0 => 0,
  1 => 3,
  2 => 1,
  3 => 4,
  4 => 2,
  5 => 5,
)

As a funky little function-less approach, you can push the $a1 value from the foreach() value declaration and inside the loop's body, you can push the $a2 value. Feast your eyes... (Demo)

$result = [];
foreach ($a1 as $index => $result[]) {
    $result[] = $a2[$index];
}
var_export($result);
// same output as earlier snippet

For anyone that is hunting for an associative-safe technique, you could make looped slice or splice calls. Be aware that splice() will mutate/consume the input arrays in the process. (Slice Demo) (Splice Demo)

$result = [];
for ($i = 0, $count = count($a1); $i < $count; ++$i) {
    $result += array_slice($a1, $i, 1)
        + array_slice($a2, $i, 1);
}

or

$result = [];
while($a1 && $a2) {
    $result += array_splice($a1, 0, 1)
        + array_splice($a2, 0, 1);
}

p.s. I even build this utility snippet to offer more dynamic tooling of how many elements should be inserted and how frequently from each array while merging. See Insert elements from one array (one-at-a-time) after every second element of another array (un-even zippering).

Caveat: The above solutions were built for the asked question which has two arrays of equal length. If dealing with unequal arrays, you will need to determine how you wish the excess elements to be positioned in the result. Typically, it will be desirable to append the excess elements to the end of the result array. To accomplish this, determine length of each array, then use array_splice() to separate the excess elements for later. Use one of the techniques above, then append/push/merge the extra elements to the result array.

Upvotes: 1

Dejan Marjanović
Dejan Marjanović

Reputation: 19380

$count = count($a1);
for ($i = 0; $i < $count; $i++) {
    $newArray[] = $a1[$i];
    $newArray[] = $b1[$i];
}

My work here is done.

$a1 = array(0,1,2);
$a2 = array(3,4,5);

$start = microtime(TRUE);

for($t = 0; $t < 100000; $t++)
{
    $newArray = array();
    $count = count($a1);
    for ($i = 0; $i < $count; $i++)
    {
        $newArray[] = $a1[$i];
        $newArray[] = $a2[$i];
    }
}
echo  round(microtime(TRUE) - $start, 2); # 0.6

$a1 = array(0,1,2);
$a2 = array(3,4,5);

$start = microtime(TRUE);

for($t = 0; $t < 100000; $t++)
{
    $newArray = array();
    for ($i = 0; $i < count($a1); $i++)
    {
        $newArray[] = $a1[$i];
        $newArray[] = $a2[$i];
    }
}
echo  round(microtime(TRUE) - $start, 2); # 0.85

So pre-counting array size will be ~1/4 [citation needed] (on freakin' 100.000 iterations you will gain 0.2 in total) faster. If you put count() inside loop, it will recount on every iteration. 1/4 seems to me a reasonably faster. If you are looking for compiled function, you can stop.

P.S. Benchmark is like bikini, it shows you everything, and nothing.

Upvotes: 11

Related Questions