我在按特定场景合并数组方面遇到了麻烦。搜索类似案例在这里没有结果。要清楚地了解我的要求是什么,请查看以下示例:
$array1 = [
(object) ['call_date' => '2013-10-22 00:00:00', 'first_amount' => 10],
(object) ['call_date' => '2013-10-23 00:00:00', 'first_amount' => 20],
];
$array2 = [
(object) ['call_date' => '2013-10-22 00:00:00', 'second_amount' => 30],
(object) ['call_date' => '2013-10-24 00:00:00', 'second_amount' => 40],
];
我需要什么作为输出:
Array
(
[0] => stdClass
(
[call_date] => 2013-10-22 00:00:00
[first_amount] => 10
[second_amount] => 30
)
[1] => stdClass
(
[call_date] => 2013-10-23 00:00:00
[first_amount] => 20
)
[2] => stdClass
(
[call_date] => 2013-10-24 00:00:00
[second_amount] => 40
)
)
如您所见,合并按call_date进行。合并日期下的第一个和第二个数组中的项目2013-10-22 00:00:00
,附加日期2013-10-24 00:00:00
下第二个数组中的项目。
尝试了很多array_merge、array_udiff、array_merge_recursive、array_map的组合,但没有任何帮助。
简单场景:
- 更改阵列键
- 合并递归
- 将合并的元素映射回对象 (stdClass)
例:
//change key
$workFirstArray = array_combine(
array_map(function($object) { return $object->call_date;}, $firstArray), $firstArray
);
$workSecondArray = array_combine(
array_map(function($object) { return $object->call_date;}, $secondArray), $secondArray
);
//map merged elements back to StdClass
$result = array_map(function($element) {
if(is_array($element)) {
$element['call_date'] = end($element['call_date']);
$element=(object)$element;
}
return $element;
},
array_merge_recursive($workFirstArray, $workSecondArray)
);
输出:
Array
(
[0] => stdClass Object
(
[call_date] => 2013-10-22 00:00:00
[first_amount] => 10
[second_amount] => 40
)
[1] => stdClass Object
(
[call_date] => 2013-10-23 00:00:00
[second_amount] => 30
)
[2] => stdClass Object
(
[call_date] => 2013-10-24 00:00:00
[second_amount] => 40
)
)
$result = array();
$result = $firstArray;
for ($i=0; $i < count($firstArray); $i++){
for ($j=0; $j < count($secondArray); $j++){
if ($firstArray[$i]['call_date'] == $secondArray[$j]['call_date']){
$result[$i]['second_amount'] = $secondArray[$j]['second_amount'];
break;
}
}
if ($j == count($secondArray))
$result[] = $secondArray[$j-1];
}
var_dump($result);
$result = $first;
$amounts = array('first_amount','second_amount');
foreach ($first as $fKey => $f) {
foreach ($second as $sKey => $s) {
if ($f['call_date'] == $s['call_date']) {
foreach ($amounts as $amount) {
if (!isset($f[$amount]) && isset($s[$amount]))
$result[$fKey][$amount] = $s[$amount];
}
unset($second[$sKey]);
break;
}
}
}
$result = array_merge($result, $second);
如果您有更多键添加金额数组,如果要替换现有键,请从条件中删除!isset($f[$amount]) &&
,并且您有多个相等的call_date也删除break;
。
由于对象需要的处理方式与数组略有不同,因此不能简单地对对象使用数组合并技术。 在我看来,最好合并两个数组,然后迭代行/对象。
迭代时,生成一个新数组,其中组标识值用作第一级键。
对象不需要暂时转换为数组,然后恢复到其初始对象类型 - 我发现这种方法是间接的,并且可能效率低下。
数组和对象之间的另一个区别是,数组在使用方括号语法推送时不需要声明其父元素,但对于对象,您必须在将子对象推送到父对象之前声明父对象。
下面我使用空合并赋值运算符 ( ??=
) 作为仅在父对象尚未声明时声明空父对象的方法。
将每个对象的每个属性(键和值)推入其组。 完成后,您可以使用 array_values()
删除第一级关联键。
(下面两个代码段的演示)(或演示将??=
替换为isset()
条件)
函数式代码:
var_export(
array_values(
array_reduce(
array_merge($array1, $array2),
function($result, $obj) {
$result[$obj->call_date] ??= (object) [];
foreach ($obj as $prop => $val) {
$result[$obj->call_date]->$prop = $val;
}
return $result;
}
)
)
);
或没有空合并赋值
var_export(
array_values(
array_reduce(
array_merge($array1, $array2),
function($result, $obj) {
if (!isset($result[$obj->call_date])) {
$result[$obj->call_date] = $obj;
} else {
foreach ($obj as $prop => $val) {
$result[$obj->call_date]->$prop = $val;
}
}
return $result;
}
)
)
);
经典法:
$result = [];
foreach (array_merge($array1, $array2) as $obj) {
$result[$obj->call_date] ??= (object) [];
foreach ($obj as $prop => $val) {
$result[$obj->call_date]->$prop = $val;
}
}
var_export(array_values($result));
或没有空合并赋值
$result = [];
foreach (array_merge($array1, $array2) as $obj) {
if (!isset($result[$obj->call_date])) {
$result[$obj->call_date] = $obj;
} else {
foreach ($obj as $prop => $val) {
$result[$obj->call_date]->$prop = $val;
}
}
}
var_export(array_values($result));
我不赞成在另一个数组的另一个循环中使用一个数组的循环,除非组标识值是用作数组键时会发生变化的数据类型。 (例如,浮点值在用作键时将作为整数下限)