Reputation: 1377
I have from 3 to 10 arrays containing 20 to 50 value each.
I want to merge them into a single, flat, indexed array, but not the way array_merge
works.
I rather want to take the 1st value of the 1st array, then the 1st value of the second array, then the 1st value of the third array and so on.
Keys are not an issue here, It could be numerical or associative array, I'm just keeping the values, not the original keys.
Values in real application can be mixed so merging and sorting afterwards is not an option.
So if I had 3 arrays like so:
$array1 = array('1-1', '1-2', '1-3');
$array2 = array('2-1', '2-2', '2-3', '2-4');
$array3 = array('3-1', '3-2');
I would need the result to be an array containing the value in this order:
1-1, 2-1, 3-1, 1-2, 2-2, 3-2, 1-3, 2-3, 2-4
So far I have this piece of code :
$array = array($array1, $array2, $array3);
$newarray = array();
foreach ($array as $a) {
$v = array_shift($a);
if (isset($v)) {
$newarray[] = $v;
}
}
print_r($newarray);
but, of course, it only runs the 1st set of value and give me:
Array ( [0] => 1-1 [1] => 2-1 [2] => 3-1 )
array_shift
is what I need here because it remove the value from the old array (I don't need it anymore) and I move it to the new array (if it isset
). see: http://php.net/manual/en/function.array-shift.php
I'm pretty sure I will need a function and loop it until all arrays are empty, but I just can't wrap my head around this one. Any help will be greatly appreciated. Or even better if someone knows a native php function that does that.
Upvotes: 2
Views: 298
Reputation: 47904
While it is sexy to use array_map()
to transpose array data so that columns of data can be easily extracted, the problem is that when processing data structures which are not perfectly shaped matrices, you will have null
values generated.
Other answers fix the null
population by calling array_filter()
to mop up all of the unwanted null
s, but this will do harm to your result if you have false
, null
or zero-ish values in your data set that you actually wish to keep.
Also, this question states that key may be numeric or associative. This is another reason why transposing with array_map()
is less attractive -- because it will choke on arrays with non-numeric keys.
While less elegant and sexy than some earlier posted answers, this answer wins out in terms of reliability because it will never destroy falsey values.
Add all arrays into a parent array (container), then iterate those arrays one at a time. "Shift" the first element off of each array and push it into the result array. If an array has no more elements, then unset()
it so that it no longer occurs as a child of the parent array. (The original array variable will not be destroyed; only its copied version which exists inside the container.)
When the parent array has no more children, then stop looping.
Code: (Demo)
$array1 = [2 => 0, 0 => 1, 1 => '2'];
$array2 = [false, true, 'false' => false, 'true' => true];
$array3 = [null, 'null'];
$all = [$array1, $array2, $array3];
$result = [];
while ($all) {
foreach ($all as $index => &$array) {
$result[] = array_shift($array);
if (!$array) {
unset($all[$index]);
}
}
}
var_export($result);
Output:
array (
0 => 0,
1 => false,
2 => NULL,
3 => 1,
4 => true,
5 => 'null',
6 => '2',
7 => false,
8 => true,
)
Upvotes: 0
Reputation: 9072
Here's a simple one-liner...
$arr1 = ['1-1', '1-2', '1-3'];
$arr2 = ['2-1', '2-2', '2-3', '2-4'];
$arr3 = ['3-1', '3-2'];
$result = array_filter(call_user_func_array(array_merge, array_map(null, $arr1, $arr2, $arr3)));
So, maybe not so simple... Some explanation.
array_map(null, ...);
makes use of the feature of array_map
explained in example 4 of the PHP docs but without any transformation to the values (hence, null).
So, this will give you:
array(4) {
[0]=>
array(3) {
[0]=>
string(3) "1-1"
[1]=>
string(3) "2-1"
[2]=>
string(3) "3-1"
}
[1]=>
array(3) {
[0]=>
string(3) "1-2"
[1]=>
string(3) "2-2"
[2]=>
string(3) "3-2"
}
[2]=>
array(3) {
[0]=>
string(3) "1-3"
[1]=>
string(3) "2-3"
[2]=>
NULL
}
[3]=>
array(3) {
[0]=>
NULL
[1]=>
string(3) "2-4"
[2]=>
NULL
}
}
Then, we need to "flatten" the array, concatenating all the sub-arrays together.
This is achieved using array_merge
, but that doesn't take an array, so we use call_user_func_array
to feed the array into it's arguments.
Then the array_filter
to remove the nulls (introduced by array_map
due to the original arguments not being the same length).
Upvotes: 3
Reputation: 24405
Just added for reference, if you're running PHP 5.6+ you can take advantage of the new ...
operator to signify n number of arguments in a function declaration and/or call. Implementation would be something like this (reference):
function merge_vertical(...$arrays) {
return array_filter(array_merge(...array_map(null, ...$arrays)));
}
print_r(merge_vertical($array1, $array2, $array3));
Array
(
[0] => 1-1
[1] => 2-1
[2] => 3-1
[3] => 1-2
[4] => 2-2
[5] => 3-2
[6] => 1-3
[7] => 2-3
[10] => 2-4
)
Upvotes: 2
Reputation: 849
I would recommend hashing through all of the arrays in a for
loop.
$array1=array('1-1','1-2','1-3');
$array2=array('2-1','2-2','2-3','2-4','2-5');
$array3=array('3-1','3-2');
$maxSize=max(count($array1),count($array2),count($array3));
$array=array($array1,$array2,$array3);
$newarray=array();
for ($i = 0; $i < $maxSize; $i++) {
for ($x = 0; $x < count($array); $x++) {
if(count($array[$x]) > $i){
$newarray[] = $array[$x][$i];
}
}
}
print_r($newarray);
Upvotes: 1
Reputation: 17576
Try this code
$array1=array('1-1','1-2','1-3');
$array2=array('2-1','2-2','2-3','2-4');
$array3=array('3-1','3-2');
$array=array($array1,$array2,$array3);
$array2 = $array ;
function cmp($a, $b){
return (count($b) - count($a));
}
usort($array2, 'cmp');
$xax_length = count($array2[0]);
$newarray=array();
for($i=0;$i<$xax_length;$i++) {
foreach($array as &$a){
$v=array_shift($a);
if(isset($v)){
$newarray[]=$v;
}
}
}
print_r($newarray);
Upvotes: 1