如何合并多个未知深度的平面数组,转置它们,然后形成一维数组?

Posted

技术标签:

【中文标题】如何合并多个未知深度的平面数组,转置它们,然后形成一维数组?【英文标题】:How can I merge multiple flat arrays of unknown depth, transpose them, then form a 1-dimensional array? 【发布时间】:2013-10-29 00:40:11 【问题描述】:

我有 3 个这样的数组:

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

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

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

我喜欢这样的东西:

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

我怎样才能做到这一点并享受使用超过 3 个输入数组的能力?

编辑:

我试过这个:

$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);

输出: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 )

这可行,但代码不是很好。谁有更好的解决方案?

解决方案: 我用一些动态功能更新了@salathe 的帖子

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

【问题讨论】:

如果数组大小不同,或者它们的键不是从0连续编号会发生什么? 数组可以有不同的大小......合并应该还在继续...... 要求代码的问题必须表明对所解决问题的最低理解。包括尝试的解决方案,以及它们为什么不起作用。 但是以什么方式继续呢?假设在上面的示例中$b = ['b1','b2'];;结果数组应该以[...,'a3','b1','c3'] 结尾(即数组$b 回到开头),还是“b”位置应该为空,或者它应该包含一些默认值,还是应该完全省略?您需要更明确地定义您的需求。 @JuKe:但是他们保证被连续键入吗?或者一个数组可能缺少一个元素,例如只包含键 1 和 3? 【参考方案1】:

这个逻辑很烂..虽然有效

<?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);

输出:

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

【讨论】:

如果我使用array_merge,我得到这样的结果:Array ([0] => a1 [1] => a2 [2] => a3 [3] => b1 [4] = > b2 [5] => b3 [6] => c1 [7] => c2 [8] => c3 ) 是的,好的。这似乎符合最低要求,所以我删除了我的反对票;虽然它仍然没有解决如果数组没有自然键控会发生什么。 但是 OP 提到 the arrays all start with 0 and all keys are numeric. 实际上我没有得到你想说的东西。能说的准确一点吗? @ShankarDamodaran:重点应该放在效率上……你运行数组两次…… 我试图说明的是,如果数组$a[2] 实际上被键入为$a[10](但数组中没有其他元素),则会出现危险:在这种情况下, 你的计数器 $i 永远不会达到 10 的值(因为它的限制 $val 设置为最大数组的大小,仍然是 5);因此该元素永远不会进入结果。【参考方案2】:

假设 count($a)=count($b)=count($c) ,可以这样做:

<?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);
 ?>

这将导致:

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

编辑:@eggyal 我试过了:

<?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);
?>

这导致:

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 )

我不确定这是否让您满意。但是,我认为合并仍然发生。但是,它不会保留密钥。

【讨论】:

-1 "the arrays can have differenz sizes... the merging shoud still go on.."。如果每个数组没有用从 0 开始的连续数字进行数字键控,还会发生什么? 为什么不尝试合并所有数组并对其进行排序。 我不确定我明白这意味着什么?您打算如何进行排序? 感谢您的编辑,但您会注意到您的结果现在不是 OP 所需的顺序。具体来说,排序恰好将最初是数组 $a 的元素放在最初位于 $b 等的元素之前。此外,它取决于值,我确信这不是所需的行为。【参考方案3】:

需要一些编码:

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

【讨论】:

+1 非常好的解决方案。我只会强调碰撞的非数字键会被覆盖,但是很容易看出如果需要的话如何改变它。 您可能还想在开始之前reset() 数组游标,以防万一。【参考方案4】:

你可以这样做:

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

【讨论】:

如果每个数组没有用从 0 开始的连续数字以数字方式键入会发生什么? 如果他们没有按数字键,则 OP 没有指定他们想要发生的事情。如果数字不连续,则需要在运行此代码之前使它们连续 - 这很简单。鉴于这个问题,这是一个有效的解决方案。也许你可以发布你的? 同意。有了这些额外的警告,你就会得到我的 +1 :)【参考方案5】:

您可以使用array_map() 函数来完成大部分繁重的工作。

在示例中,循环内的代码仅从每个数组中获取值(null,如果没有对应的值),如果有值,则将它们附加到 $results 数组中。

示例

$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);

输出

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',
)

【讨论】:

除了写array_map(null, $a, $b, $c, $d)之外,如何使用超过3个数组来执行此操作 @JuKe 是的,只需在array_map 调用中添加更多数组即可。 @eggyal 试试看。 @salathe:我写了......“除了写array_map(null, $a, $b, $c, $d)”有各种数量的数组 @JuKe 首先,请在问题中更清楚地添加这一点(“意见”部分令人困惑,您的意思是“选项”吗?)。其次,有多少数组不影响上面使用的合并数组的方法。如果需要,您可以动态调用array_map()(例如使用call_user_func_array())。【参考方案6】:

您的案例只是与一些特定的顺序合并。这样做的明确方法是:

    合并数组 排序结果

代码示例:

$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);

输出:

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

有更通用的解决方案(所有第一行都是后续的,所有第二行都是后续的......):

$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);

【讨论】:

这个解决方案完全依赖于所涉及的值,我怀疑这应该是偶然的;实际上,我认为问题中描述的值只是为了说明所需行为而设计的示例。 好的,问题不清楚。我将编辑和添加数据独立解决方案【参考方案7】:

对不起我之前的回答,误读了这个问题。这是您需要的:

$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]);
            
        
    

即使是大小不等的数组:

$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'
);

你会得到结果:

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

【讨论】:

【参考方案8】:

可以通过排序来完成

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

【讨论】:

这个解决方案完全依赖于所涉及的值,我怀疑这应该是偶然的;实际上,我认为问题中描述的值只是为了说明所需行为而设计的示例。 可能是这样,但是胎面启动器已经明确询问了这些值,并且从未提及任何其他模式。所以我简单地给出了答案。【参考方案9】:

在找到此页面之前,我回答了一个重复项。我下面的解决方案使用...$row 作为输入数据,但对于这个问题,只需将...$rows 切换为$a, $b, $c。 (我已经删除了我的其他答案,并使用此页面敲定了重复的问题。

我对功能性单行代码的看法(为了便于阅读,我已将其拆分并标记了标签)如下。请注意,早期过滤意味着最大限度地减少“无用数据”处理,而后期过滤将减少函数调用。

贪婪/懒惰/虚假过滤的后期过滤:(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
);

简洁的单行语法:(Demo)

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

带有贪婪/懒惰/虚假过滤的中间过滤:(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
);

或者进行早期过滤...(使用贪婪/懒惰/虚假过滤)

代码:(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
);

或使用贪婪/懒惰/虚假过滤和更多“喷溅”的早期过滤:(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
);

这里是 PHP7.4 版本:(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
);

浓缩为:

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

【讨论】:

以上是关于如何合并多个未知深度的平面数组,转置它们,然后形成一维数组?的主要内容,如果未能解决你的问题,请参考以下文章

在八叉树中合并叶子

如何将同一属性上的数组和对象“合并/合并”到平面数组中(使用Javascript)?

按列合并多个 csv 文件的最快方法是啥?

MATLAB中如何画平行x轴或y的直线?

将平面数组转换为分层的多维数组

合并或合并索引不相等的两个或三个(多于三个)数组