根据共享列值合并两个二维数组的行,并在缺少预期列的情况下应用默认值

问题描述 投票:0回答:3

我有两个数组,必须在

dt_date
列上合并在一起,并且我需要在结果的所有行中声明
subscribers
unsubscribers

$array1 = [
    ['subscribers' => 2, 'dt_date' => '2014-02-27'],
    ['subscribers' => 2, 'dt_date' => '2014-02-25'],
    ['subscribers' => 1, 'dt_date' => '2014-02-07']
];
$array2 = [
    ['unsubscribers' => 1, 'dt_date' => '2014-02-27'],
    ['unsubscribers' => 1, 'dt_date' => '2014-02-01']
];

我需要从两个数组创建一个如下所示的数组。

[
    ['subscribers' => 2, 'unsubscribers' => 1, 'dt_date' => '2014-02-27'],
    ['subscribers' => 2, 'unsubscribers' => 0, 'dt_date' => '2014-02-25'],
    ['subscribers' => 1, 'unsubscribers' => 0, 'dt_date' => '2014-02-07'],
    ['subscribers' => 0, 'unsubscribers' => 1, 'dt_date' => '2014-02-01']
]

我试过了

$result = array_merge_recursive($aray1, $array2);

并且

$result = array_merge(
    $array1, 
    array_udiff(
        $array2,
        $array1, 
        function($array1,$array2){
            return strcmp($array1['dt_date'],$array2['dt_date']);
        }
    )
);  

但是结果却没有想象中的那样

php arrays multidimensional-array merge grouping
3个回答
1
投票

实际上,你的问题可以用一些

foreach
的东西来解决,但我注意到你正在尝试模拟某种 SQL
JOIN
行为(将
ON
列作为
dt_date
)。这就是为什么我花了更多时间并创建了更常见的解决方案。

首先,我们需要重新索引数组,以便我们可以更快地使用它们:

function reindexArray($array, $column)
{
   return array_combine(
                array_map(function($x) use ($column)
                {
                   return $x[$column];
                }, $array),
                $array
   );
}

上面的函数可以很容易地用

array_column()
调用替换,但我假设你有 PHP 5.3,因此你需要“手动”重新索引。

接下来,加入逻辑:

function arrayJoin($array1, $array2, $column, $default=null)
{
   //in PHP 5.5 it's just array_column() call:
   $array1 = reindexArray($array1, $column);
   $array2 = reindexArray($array2, $column);
   $blank1 = array_combine(
                array_keys(current($array1)), 
                array_fill(1, count(current($array1)), $default)
   );
   $blank2 = array_combine(
                array_keys(current($array2)), 
                array_fill(1, count(current($array2)), $default)
   );
   unset($blank1[$column], $blank2[$column]);

   return array_merge(
             array_map(function($x) use ($array1, $blank2)
             {
                return array_merge($array1[$x], $blank2);
             }, array_keys(array_diff_key($array1, $array2))),
             array_map(function($x) use ($array1, $array2)
             {
                return array_merge($array1[$x], $array2[$x]);
             }, array_keys(array_intersect_key($array1, $array2))),
             array_map(function($x) use ($array2, $blank1)
             {
                return array_merge($array2[$x], $blank1);
             }, array_keys(array_diff_key($array2, $array1)))
   );
}

- 正如您所看到的,您还需要决定如何处理每个连接数组的未设置键。

$default
将为您填写该值。因此,您的问题将通过以下方式解决:

$result = arrayJoin($array1, $array2, 'dt_date', 0);

-检查这个演示

但是,如果您的原始数组源自某些 SQL 数据库,那么更好的做法是将

JOIN
逻辑放在那里 - 因为数据库的目的是存储数据并正确选择它。


0
投票

我找到答案了

 $result= array_replace_recursive($array1,$array2);
 foreach ($result as $key => $value) {
    if(!isset($value['unsubscribers']))
        $result[$key]['unsubscribers']=0;
    if(!isset($value['subscribers']))
        $result[$key]['subscribers']=0;
 }

谢谢你


0
投票
  1. 合并两个数组并循环它们。
  2. 在将数据推送到结果数组时分配临时的第一级键,以便您可以快速识别随后遇到的相关行。
  3. 如果之前没有遇到过该日期,则将该行的数据与默认行合并,以便表示所有预期的元素。
  4. 如果在第一次之后遇到给定日期,请将存储的行与新行合并,以便新行的数据覆盖默认值。
  5. 完成迭代后,使用
    array_values()
    重新索引结果数组(这会删除临时的第一级键)。

代码:(演示

$result = [];
$default = array_fill_keys(['subscribers', 'unsubscribers'], 0);
foreach (array_merge($array1, $array2) as $row) {
    $result[$row['dt_date']] = array_merge($result[$row['dt_date']] ?? $default, $row);
}
var_export(array_values($result));

功能风格的等价物:(Demo)

$default = array_fill_keys(['subscribers', 'unsubscribers'], 0);
var_export(
    array_values(
        array_reduce(
            array_merge($array1, $array2),
            function($result, $row) use($default) {
                $result[$row['dt_date']] = array_merge($result[$row['dt_date']] ?? $default, $row);
                return $result;
            }
        )        
    )
);
© www.soinside.com 2019 - 2024. All rights reserved.