How can I merge multiple flat arrays of unknown depth, transpose them, then form a 1-dimensional array?

你说的曾经没有我的故事 提交于 2020-06-23 08:58:27

问题


I have 3 arrays like this:

$a = array(
 0 => 'a1',
 1 => 'a2',
 2 => 'a3'
);

$b = array(
 0 => 'b1',
 1 => 'b2',
 2 => 'b3'
);

$c = array(
 0 => 'c1',
 1 => 'c2',
 2 => 'c3'
);

and I like to have something like this:

$r = array(
 0 => 'a1',
 1 => 'b1',
 2 => 'c1',
 3 => 'a2',
 4 => 'b2',
 5 => 'c2',
 6 => 'a3',
 ....
 ...
);

How can I do this AND enjoy the ability to use more then 3 input arrays?

EDIT:

I have tried this:

$a = array(
        0 => 'a1',
        1 => 'a2',
        2 => 'a3',
        3 => 'a4'
    );
    $b = array(
        0 => 'b1',
        1 => 'b2',
        2 => 'b3'
    );
    $c = array(
        0 => 'c1',
        1 => 'c2',
        2 => 'c3',
        3 => 'c4',
        4 => 'c5',
        5 => 'c6'

    );

    $l['a'] = count($a);
    $l['b'] = count($b);
    $l['c'] = count($c);

    arsort($l);
    $largest = key($l);
    $result = array();
    foreach ($$largest as $key => $value) {
        $result[] = $a[$key];
        if(array_key_exists($key, $b)) $result[] = $b[$key];
        if(array_key_exists($key, $c)) $result[] = $c[$key];

    }
    print_r($result);

Output: Array ( [0] => a1 [1] => b1 [2] => c1 [3] => a2 [4] => b2 [5] => c2 [6] => a3 [7] => b3 [8] => c3 [9] => a4 [10] => c4 [11] => [12] => c5 [13] => [14] => c6 )

This works but the code isn't nice. Does anyone have a better solution?

Solution: I updated the post from @salathe with some dynamic feature

function comb(){
    $arrays = func_get_args();
    $result = array();
    foreach (call_user_func_array(array_map, $arrays) as $column) {
        $values = array_filter($column, function ($a) { return $a !== null; });
        $result = array_merge($result, $values);
    }
    return $result;
}
print_r(comb(null,$a,$b,$c,$d,....));

回答1:


You could make use the array_map() function to do most of the hard work.

In the example, the code inside the loop just takes the value from each array (null if there is not a corresponding value) and if there is a value, appends them to the $results array.

Example

$result = array();
foreach (array_map(null, $a, $b, $c) as $column) {                                          
    $values = array_filter($column, function ($a) { return $a !== null; });
    $result = array_merge($result, $values);
}
var_export($result);

Output

array (
  0 => 'a1',
  1 => 'b1',
  2 => 'c1',
  3 => 'a2',
  4 => 'b2',
  5 => 'c2',
  6 => 'a3',
  7 => 'b3',
  8 => 'c3',
  9 => 'a4',
  10 => 'c3',
  11 => 'c3',
  12 => 'c3',
)



回答2:


Need some coding:

function customMerge()
{
    $arrays = func_get_args();
    $res = array();
    $continue = true;
    while($continue){
       $continue = false;
       for($j=0;$j<count($arrays); $j++){
          if($pair = each($arrays[$j]){
              if(is_numeric($pair[0])
                  $res[] = $pair[1];
              else
                  $res[ $pair[0] ] = $pair[1];
              $continue = true;
          }
       }
    }
    return $res;
}  

$res = customMerge($arr1, $arr2, $arr3, ...);



回答3:


sorry for my previous answer, misread the question. here's what you need:

$arrays = array($a,$b,$c);

$new = array();

$count = count($arrays);
while(count($arrays) > 0) {

    for($i = 0; $i < $count; $i++) {
        if (isset($arrays[$i])) {
        array_push($new, array_shift($arrays[$i]));
        if (count($arrays[$i]) == 0) {
            unset($arrays[$i]);
            }
        }
    }
}

even for the arrays with not equal sizes:

$a = array(
 0 => 'a1',
 1 => 'a2',
 2 => 'a3',
 3 => 'a4'
);

$b = array(
 0 => 'b1',
 1 => 'b2',
 2 => 'b3'
);

$c = array(
 0 => 'c1',
 1 => 'c2',
 2 => 'c3',
 3 => 'c4'
);

you'll get the result:

Array
(
    [0] => a1
    [1] => b1
    [2] => c1
    [3] => a2
    [4] => b2
    [5] => c2
    [6] => a3
    [7] => b3
    [8] => c3
    [9] => a4
    [10] => c4
)



回答4:


You could do something like this:

function getMaxLength(array $arrays) {
    $len = count($arrays);

    if($len == 0) {
        return 0;
    }

    $max = count($arrays[0]);
    for($i = 1; $i < $len; $i++) {
        $count = count($arrays[$i]);
        if($count > $max) {
            $max = $count;
        }
    }

    return $max;
}

function combine() {
    $arrays = func_get_args();
    $maxLength = getMaxLength($arrays);
    $combined = array();
    for($i = 0; $i < $maxLength; $i++) {
        foreach($arrays as $array) {
            if(isset($array[$i])) {
                $combined[] = $array[$i];
            }
        }
    }
    return $combined;
}

print_r(combine($a, $b, $c));



回答5:


This logic sucks.. Works though

<?php

$a = array(
    0 => 'a1',
    1 => 'a2',
    2 => 'a3'
);

$b = array(
    0 => 'b1',
    1 => 'b2',
    2 => 'b3'
);

$c = array(
    0 => 'c1',
    1 => 'c2',
    2 => 'c3',
    3 => 'c4',
    4 => 'c5' 
);

$val=5; //Size of the largest array  (largest array is c)

$d=array();
for($i=0;$i<$val;$i++)
{
    $d[]=$a[$i];
    $d[]=$b[$i];
    $d[]=$c[$i];
}

//Clearing empty values
foreach ($d as $key=>$value)
if (empty($value))
    unset($d[$key]);



 //Consecutive Keys 
       $finalArray = array_values($d);
       print_r($finalArray);

OUTPUT :

Array ( [0] => a1 [1] => b1 [2] => c1 [3] => a2 [4] => b2 [5] => c2 [6] => a3 [7] => b3 [8] => c3 [9] => c4 [10] => c5 )



回答6:


Assumed count($a)=count($b)=count($c) , this can be done as:

<?php
   $var = array();
   for($i=0;$i<count($a);$i++)
   {
    array_push($var,$a[$i]);
    array_push($var,$b[$i]);
    array_push($var,$c[$i]);
    }
  print_r($var);
 ?>

This will result in:

Array ( [0] => a1 [1] => b1 [2] => c1 [3] => a2 [4] => b2 [5] => c2 [6] => a3 [7] => b3 [8] => c3 )

Edit: for @eggyal
I tried this out:

<?php
 $a = array(
    0 => 'a1',
    1 => 'a2',
    2 => 'a3',
    3 => 'a4'
);
$b = array(
    'x' => 'b1',
    'y' => 'b4',
    'z' => 'b3'
);
$c = array(
    0 => 'c1',
    'p' => 'c2',
    2 => 'c3',
    3 => 'c3',
    'q' => 'c3',
    5 => 'c3'

);
$d = array_merge($b,$a,$c);//place arrays in any order like $a,$b,$c or $b,$a,$c or $c,$b,$a
sort($d);
print_r($d);
?>

This resulted in:

Array ( [0] => a1 [1] => a2 [2] => a3 [3] => a4 [4] => b1 [5] => b3 [6] => b4 [7] => c1 [8] => c2 [9] => c3 [10] => c3 [11] => c3 [12] => c3 )

I am not sure this satisfies you or not. But, i think the merging still takes place. However, it does not preserve the keys.




回答7:


Can be done with sorting

$arr = array_merge($a,$b,$c);

foreach ($arr as $key => $val) {
  $numsort[$key] = substr($val,1);
  $charsort[$key] = substr($val,0,1);
}

array_multisort($arr, SORT_ASC, SORT_NUMERIC, $numsort, $arr, SORT_ASC, $charsort);

// result

Array
(
    [0] => a1
    [1] => b1
    [2] => c1
    [3] => a2
    [4] => b2
    [5] => c2
    [6] => a3
    [7] => b3
    [8] => c3
)



回答8:


Your case is just merge with some specific ordering. So clear way to do that is:

  1. merge arrays
  2. sort result

Code example:

$merged = array_merge($a, $b, $c);
usort($merged, function($left, $right) {
        if (substr($left, 1) == substr($right, 1)) {//if numbers equal check letters
                return (substr($left, 0, 1) < substr($right, 0, 1)) ? -1 : 1;
        }
        return (substr($left, 1) < substr($right, 1)) ? -1 : 1;
});

print_r($merged);

output:

Array
(
    [0] => a1
    [1] => b1
    [2] => c1
    [3] => a2
    [4] => b2
    [5] => c2
    [6] => a3
    [7] => b3
    [8] => c3
)

There is more generic solution (all first rows are subsequent, all second rows all subsequent ...):

$result = call_user_func_array('array_merge', array_map(
        function () {
                return array_filter(func_get_args(), function ($element) {
                                return $element !== null;
                });
        } , $a, $b, $c)
);

print_r($result);




回答9:


I answered a duplicate before finding this page. My solutions below use ...$row for the input data, but for this question just switch ...$rows for $a, $b, $c. (I have since deleted my other answer and hammered the duplicate question using this page.)

My thoughts on functional one-liners (I've split it and tabbed it for readability) are as follows. Note that early filtering will mean minimizing "useless data" handling and late filtering will make fewer function calls.

Late filtering with greedy/lazy/falsey filtering: (Demo)

var_export(
    array_filter(          #remove nulls
        array_merge(       #flatten the unpacked elements
            ...array_map(  #unpack
                null,      #transpose
                ...$rows   #transpose
            )              #unpack
        )                  #flatten the unpacked elements    
    )                      #remove nulls
);

Condensed one-liner syntax: (Demo)

var_export(array_filter(array_merge(...array_map(null, ...$rows))));

Intermediate filtering with greedy/lazy/falsey filtering: (Demo)

var_export(
    array_merge(              #flatten the unpacked elements
        ...array_filter(      #remove nulls from transposing then unpack
            array_map(        #transpose
                null,         #transpose
                ...$rows      #transpose
            )                 #transpose
        )                     #remove nulls from transposing then unpack
    )                         #flatten the unpacked elements
);

Or do early filtering... (with greedy/lazy/falsey filtering)

Code: (Demo)

var_export(
    array_merge(                     #flatten the unpacked elements
        ...array_map(                #unpack
            function() {             #transpose discarding nulls
                return array_filter( #transpose discarding nulls
                    func_get_args()  #transpose discarding nulls
                );                   #transpose discarding nulls
            },                       #transpose discarding nulls
            ...$rows                 #transpose discarding nulls
        )                            #unpack
    )                                #flatten the unpacked elements
);

Or early filtering with greedy/lazy/falsey filtering and more "splatting": (Demo)

var_export(
    array_merge(                         #flatten the unpacked elements
        ...array_map(                    #unpack
            function(...$v) {            #transpose discarding nulls
                return array_filter($v); #transpose discarding nulls
            },                           #transpose discarding nulls
            ...$rows                     #transpose discarding nulls
        )                                #unpack
    )                                    #flatten the unpacked elements
);

And here is the PHP7.4 version: (Demo)

var_export(
    array_merge(                           #flatten the unpacked elements
        ...array_map(                      #unpack
            fn(...$v) => array_filter($v), #transpose discarding nulls
            ...$rows                       #transpose discarding nulls
        )                                  #unpack
    )                                      #flatten the unpacked elements
);

Which condenses as:

var_export(array_merge(...array_map(fn(...$v) => array_filter($v), ...$rows)));


来源:https://stackoverflow.com/questions/19478981/how-can-i-merge-multiple-flat-arrays-of-unknown-depth-transpose-them-then-form

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!