如何合并多个未知深度的平面数组,转置它们,然后形成一维数组?
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)));
【讨论】:
以上是关于如何合并多个未知深度的平面数组,转置它们,然后形成一维数组?的主要内容,如果未能解决你的问题,请参考以下文章