5

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.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
qwertymk
  • 34,200
  • 28
  • 121
  • 184
  • I'm not sure why a build-in function would be faster? This is basically what you want to do, isn't it? – Nanne Aug 06 '12 at 11:37
  • I guess you could store elements of one array in odd positions and elements of other array at even position if you want to merge them in an alternate sequence. – Fyre Aug 06 '12 at 11:38
  • @qwertymk I know you say performance is an issue, but I would be surprised if a built-in function would be noticably (if at all) faster than the loop approach, since any built in function would just have a C++ loop underneath it anyway. – DaveRandom Aug 06 '12 at 11:41
  • 1
    @DaveRandom Well I know nothing about how PHP expands arrays, are they linked list in memory? Maybe a built in function would first alloc memory for the array once and then start inserting values. Not knowing any of the above... I asked this question. – qwertymk Aug 06 '12 at 11:44
  • @qwertymk Firstly, you are slightly over-thinking it there, IMHO. The theoretical performance gains you are talking about are microseconds - with "thousands" of arrays that still only amounts to milliseconds. Secondly, it sounds like you are coming from the concept of an array in a low-level programming language, and PHP arrays are nothing like that in terms of the way they work underneath. You might find [this](http://nikic.github.com/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.html) an interesting read, albeit not directly related to the question. – DaveRandom Aug 06 '12 at 11:47

2 Answers2

11
$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.

Dejan Marjanović
  • 19,244
  • 7
  • 52
  • 66
0

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).

mickmackusa
  • 43,625
  • 12
  • 83
  • 136