合并多维数组并尽可能保留非空值
Merge a multidimensional array and retain non-empty values when possible
我有一个具有以下结构的关联数组(实际上是一个 Laravel 集合):
$array = [
["firstname" => "John", "lastname" => "", "email" => "", "uri" => ""],
["firstname" => "", "lastname" => "Smith", "email" => "", "uri" => ""],
["firstname" => "", "lastname" => "", "email" => "john@example.org", "uri" => ""]
];
如何 combine/merge/reduce 整个多维数组,以便最终得到一个包含所有列并优先考虑非空值的扁平化结构?
像这样:
[
['firstname' => 'John', 'lastname' => 'Smith', 'email' => 'john@example.org', 'uri' => '']
]
这里我们使用array_merge
和array_filter
。 array_merge
将一个数组合并到另一个数组中,array_filter
将过滤数组中的空值。
<?php
$array = array(
0 => array(
"firstname" => "John",
"lastname" => "",
"email" => "",
"uri" => ""
),
1 => array(
"firstname" => "",
"lastname" => "Smith",
"email" => "",
"uri" => ""
),
2 => array(
"firstname" => "",
"lastname" => "",
"email" => "john@example.org",
"uri" => "")
);
$result=array();
foreach($array as $value)
{
$result= array_merge($result,array_filter($value));
}
$result["uri"]="";
print_r(array($result));
我将展示一些具有不同优势的替代技术,这些技术依赖于所有列都在所有行中表示这一事实。我看不出生成二维输出数组有任何好处,所以我的所有代码片段都将生成相同的平面关联数组。
无论您喜欢哪种风格,都至少需要两个循环——一个用于迭代行,一个用于迭代每行中的元素。
标准嵌套循环:(Demo)
$result = array_shift($array); // remove the first row and push it into the result array
foreach ($array as $row) {
foreach ($row as $key => $value) {
if ($value !== '') {
$result[$key] = $value; // only overwrite where a non-empty value exists
}
}
}
var_export($result);
基于半函数的迭代:(Demo)
$result = array_shift($array); // remove the first row and push it into the result array
foreach ($array as $row) {
$result = array_merge($result, array_filter($row, 'strlen')); // merge only non-empty elements into the result
}
var_export($result);
*请注意,以防万一您的实际项目超过您发布的四个字段并且其中一个字段 可能 包含您不想过滤掉的零值, 使用 strlen
作为 array_filter()
中的参数。否则,array_filter()
将贪婪地杀死 null、false、zeroish 和零宽度值。
基于 array_reduce()
的全功能:(Demo)
var_export(
array_reduce(
$array,
function($carry, $row) {
$carry = array_merge($carry, array_filter($row, 'strlen'));
return $carry;
},
array_shift($array)
)
);
基于 array_merge_recursive()
的全功能:(Demo)
var_export(
array_map('max', array_merge_recursive(...$array))
);
这是最简短的,但不可否认,它利用了 max()
将从每一列中 return 所需的字符串这一事实。这种方法作为一种通用技术可能并不适用于所有场景。
实际上,这是将 $array
解包为 $row[0], $row[1], $row[2]
(使用 ...
),然后将数据转置为列数据的子数组(使用 array_merge_recursive()
维护第一级键),然后将每个子数组减少到它的“最高”值(在每个子数组上使用 max()
)。
Sahil 的回答不是很 robust/trustworthy 因为它在过程完成后手动更正丢失的 uri
键值。进行此调整纯粹是因为缺失值对程序员来说是“已知的”。从编程上讲,这是懒惰的,容易失败,不应该被 SO 读者使用。
我有一个具有以下结构的关联数组(实际上是一个 Laravel 集合):
$array = [
["firstname" => "John", "lastname" => "", "email" => "", "uri" => ""],
["firstname" => "", "lastname" => "Smith", "email" => "", "uri" => ""],
["firstname" => "", "lastname" => "", "email" => "john@example.org", "uri" => ""]
];
如何 combine/merge/reduce 整个多维数组,以便最终得到一个包含所有列并优先考虑非空值的扁平化结构?
像这样:
[
['firstname' => 'John', 'lastname' => 'Smith', 'email' => 'john@example.org', 'uri' => '']
]
这里我们使用array_merge
和array_filter
。 array_merge
将一个数组合并到另一个数组中,array_filter
将过滤数组中的空值。
<?php
$array = array(
0 => array(
"firstname" => "John",
"lastname" => "",
"email" => "",
"uri" => ""
),
1 => array(
"firstname" => "",
"lastname" => "Smith",
"email" => "",
"uri" => ""
),
2 => array(
"firstname" => "",
"lastname" => "",
"email" => "john@example.org",
"uri" => "")
);
$result=array();
foreach($array as $value)
{
$result= array_merge($result,array_filter($value));
}
$result["uri"]="";
print_r(array($result));
我将展示一些具有不同优势的替代技术,这些技术依赖于所有列都在所有行中表示这一事实。我看不出生成二维输出数组有任何好处,所以我的所有代码片段都将生成相同的平面关联数组。
无论您喜欢哪种风格,都至少需要两个循环——一个用于迭代行,一个用于迭代每行中的元素。
标准嵌套循环:(Demo)
$result = array_shift($array); // remove the first row and push it into the result array
foreach ($array as $row) {
foreach ($row as $key => $value) {
if ($value !== '') {
$result[$key] = $value; // only overwrite where a non-empty value exists
}
}
}
var_export($result);
基于半函数的迭代:(Demo)
$result = array_shift($array); // remove the first row and push it into the result array
foreach ($array as $row) {
$result = array_merge($result, array_filter($row, 'strlen')); // merge only non-empty elements into the result
}
var_export($result);
*请注意,以防万一您的实际项目超过您发布的四个字段并且其中一个字段 可能 包含您不想过滤掉的零值, 使用 strlen
作为 array_filter()
中的参数。否则,array_filter()
将贪婪地杀死 null、false、zeroish 和零宽度值。
基于 array_reduce()
的全功能:(Demo)
var_export(
array_reduce(
$array,
function($carry, $row) {
$carry = array_merge($carry, array_filter($row, 'strlen'));
return $carry;
},
array_shift($array)
)
);
基于 array_merge_recursive()
的全功能:(Demo)
var_export(
array_map('max', array_merge_recursive(...$array))
);
这是最简短的,但不可否认,它利用了 max()
将从每一列中 return 所需的字符串这一事实。这种方法作为一种通用技术可能并不适用于所有场景。
实际上,这是将 $array
解包为 $row[0], $row[1], $row[2]
(使用 ...
),然后将数据转置为列数据的子数组(使用 array_merge_recursive()
维护第一级键),然后将每个子数组减少到它的“最高”值(在每个子数组上使用 max()
)。
Sahil 的回答不是很 robust/trustworthy 因为它在过程完成后手动更正丢失的 uri
键值。进行此调整纯粹是因为缺失值对程序员来说是“已知的”。从编程上讲,这是懒惰的,容易失败,不应该被 SO 读者使用。