我在下面的 PHP 代码中有一个数组,我想将该数组转换为按数据值分组。简化数组总是很困难。
原始数组:
$array = [
['date' => '2017-08-22', 'AAA' => 1231],
['date' => '2017-08-21', 'AAA' => 1172],
['date' => '2017-08-20', 'AAA' => 1125],
['date' => '2017-08-21', 'BBB' => 251],
['date' => '2017-08-20', 'BBB' => 21773],
['date' => '2017-08-22', 'CCC' => 3750],
['date' => '2017-08-20', 'CCC' => 321750],
];
下面是我想要的数组:
[
'2017-08-22' => ['AAA' => 1231, 'CCC' => 3750],
'2017-08-21' => ['AAA' => 1172, 'BBB' => 251],
'2017-08-20' => ['AAA' => 1125, 'BBB' => 21773, 'CCC' => 321750],
]
如果数据不存在,空值也可以。 [BBB] => 2017-08-22 为 NULL。 有人可以帮忙吗?预先感谢...
一个简单的循环就可以做到这一点..
$group = [];
foreach ($data as $item) {
if (!isset($group[$item['date']])) {
$group[$item['date']] = [];
}
foreach ($item as $key => $value) {
if ($key == 'date') continue;
$group[$item['date']][$key] = $value;
}
}
这里:这应该可以完成工作。
$dst_array = array();
foreach ($array as $outerval) {
foreach ($outerval as $key => $innerval) {
if ($key != 'date') {
$dst_array[$outerval['date']][$key] = $innerval;
}
}
}
它遍历数组,然后遍历每个子数组中的条目。任何非日期的 any 都会被分配到与其日期相对应的子数组中的目标数组中,并具有自己的当前键。
我绝对不会推荐任何涉及多个循环的技术——这一过程当然可以在单个循环中执行。
如果您喜欢语言构造迭代,请使用
foreach()
循环:(Demo)
$result = [];
foreach ($array as $row) {
$date = $row['date'];
unset($row['date']);
$result[$date] = array_merge($result[$date] ?? [], $row);
}
var_export($result);
如果您喜欢使用函数式编程和较少的全局变量,请使用
array_reduce()
:(Demo)
var_export(
array_reduce(
$array,
function($accumulator, $row) {
$date = $row['date'];
unset($row['date']);
$accumulator[$date] = array_merge($accumulator[$date] ?? [], $row);
return $accumulator;
},
[]
)
);
这些技术无条件地将数据推送到带有基于日期列值的键的子数组中。
即使子数组元素的顺序发生变化,上述技术也将始终有效。
??
(空合并运算符)是为了确保array_merge()
在第一个参数中始终有一个数组——如果处理给定日期的第一次出现,您只需合并当前迭代的数据(之后剩下的数据) unset()
删除日期元素)并使用空数组。
我相信这个解决方案适合您:
<?php
$array = Array
(
0 => Array
(
'date' => '2017-08-22',
'AAA' => '1231',
),
1 => Array
(
'date' => '2017-08-21',
'AAA' => '1172',
),
2 => Array
(
'date' => '2017-08-20',
'AAA' => '1125'
),
3 => Array
(
'date' => '2017-08-21',
'BBB' => '251'
),
4 => Array
(
'date' => '2017-08-20',
'BBB' => '21773',
),
5 => Array
(
'date' => '2017-08-22',
'CCC' => '3750'
),
6 => Array
(
'date' => '2017-08-20',
'CCC' => '321750'
)
);
echo '<pre>';
$array1 = array('AAA' => null, 'BBB' => null, 'CCC' => null);
$array2 = array();
array_walk($array, function ($v) use (&$array2, $array1) {
$a = $v['date'];
if (!isset($array2[$a])) {
$array2[$a] = $array1;
}
unset($v['date']);
$array2[$a] = array_merge($array2[$a], $v);
});
print_r($array2);
输出
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[BBB] =>
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
[CCC] =>
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
使用数组内部指针的另一种方法(快速但肮脏):
$newArray = [];
foreach ($array as $childArray) {
$date = current($childArray);
$value = next($childArray); // this advances the internal pointer..
$key = key($childArray); // ..so that you get the correct key here
$newArray[$date][$key] = $value;
}
这当然仅适用于给定的数组结构。
array_reduce()
:
// The input array
$input = array(
0 => array(
'date' => '2017-08-22',
'AAA' => '1231',
),
// The rest of your array here...
);
$output = array_reduce(
$input,
function (array $carry, array $item) {
// Extract the date into a local variable for readability and speed
// It is used several times below
$date = $item['date'];
// Initialize the group for this date if it doesn't exist
if (! array_key_exists($date, $carry)) {
$carry[$date] = array();
}
// Remove the date from the item...
// ...and merge the rest into the group of this date
unset($item['date']);
$carry[$date] = array_merge($carry[$date], $item);
// Return the partial result
return $carry;
},
array()
);
问题不清楚。如果一个键 (
AAA
f.e) 出现在两个或多个日期上,预期结果是什么?此答案仅保留与其关联的最后一个值。