【问题标题】:How to merge two arrays using column values and find sum of another column's values? [duplicate]如何使用列值合并两个数组并找到另一列值的总和? [复制]
【发布时间】:2017-08-31 08:25:22
【问题描述】:

我有两个数组,它们具有来自两个不同查询的相同键。

第一个查询结果:

Array
(
  [0] => Array
  (
      [Contribution] => 1000.00
      [P_Name] => A
  )
  [1] => Array
  (
      [Contribution] => 1500.00
      [P_Name] => B
  )
)

第二次查询结果:

Array
(
  [0] => Array
  (
      [Contribution] => 100.00
      [P_Name] => A
  )
  [1] => Array
  (
      [Contribution] => 200.00
      [P_Name] => B
  )
)

第一个数组可能是空的和/或第二个可能是空的。

我想创建一个新数组,找到 Contribution 值与 P_Name 值匹配的总和,如下所示:

Array
(
  [0] => Array
  (
      [Contribution] => 1100.00
      [P_Name] => A
  )
  [1] => Array
  (
      [Contribution] => 1700.00
      [P_Name] => B
  )
)

我试过array_merge():

$result1= $this->model1->getOthersTotal($date);
$result2=$this->model1->getMiscTotal($date);
$merged_result = array_merge( $result1, $result2 );

$merged_result 包含:

Array (
    [0] => Array (
        [Contribution] => 1000.00
        [P_Name] => A
    )
    [1] => Array (
        [Contribution] => 1001.00
        [P_Name] => A
    )
    [2] => Array (
        [Contribution] => 69.00
        [P_Name] => B
    )
)

【问题讨论】:

标签: php multidimensional-array array-merge array-sum


【解决方案1】:

输入:

$a=[['Contribution'=>1000,'P_Name'=>'A'],
    ['Contribution'=>1500,'P_Name'=>'B'],
    ['Contribution'=>2000,'P_Name'=>'C']];
$b=[['Contribution'=>100,'P_Name'=>'A'],
    ['Contribution'=>200,'P_Name'=>'B'],
    ['Contribution'=>300,'P_Name'=>'D']];

如果您使用array_column() 临时将关联键分配给子数组,那么您可以利用array_merge_recursive()P_Name 值进行分组,然后在有多个值时调用array_sum() 进行加法给定的P_Name

方法#1: (Demo)

$keyed=array_merge_recursive(array_column($a,NULL,'P_Name'),array_column($b,NULL,'P_Name'));
foreach($keyed as $p_name=>$array){
    $result[]=['Contribution'=>(is_array($array['Contribution'])?array_sum($array['Contribution']):$array['Contribution']),'P_Name'=>$p_name];
}
var_export($result);

或者只是做一个标准的合并来创建一个数组,然后循环并随时添加。使用array_values() 完成输出数组以重新索引元素。

方法#2: (Demo)

foreach(array_merge($a,$b) as $array){
    if(isset($result[$array['P_Name']])){
        $result[$array['P_Name']]['Contribution']+=$array['Contribution'];
    }else{
        $result[$array['P_Name']]=$array;
    }
}
$result=array_values($result);
var_export($result);

输出:(来自任一方法)

array (
  0 => 
  array (
    'Contribution' => 1100,
    'P_Name' => 'A',
  ),
  1 => 
  array (
    'Contribution' => 1700,
    'P_Name' => 'B',
  ),
  2 => 
  array (
    'Contribution' => 2000,
    'P_Name' => 'C',
  ),
  3 => 
  array (
    'Contribution' => 300,
    'P_Name' => 'D',
  ),
)

这超出了这个问题的范围,但最好的方法是通过数据库查询执行此分组/添加。

【讨论】:

  • @mickmackusa 如果您“相信”您的代码是最有效的,请提供基准测试。 Let me help you with thatresults。你的方法比我的慢两倍多。包含此页面上的所有方法,并提供正确(和预期)的响应。
  • 此时所做的任何基准测试都将是推测性的,因为我们不知道 OP 的潜在数组大小或 OP 的 php 版本。但是你提供早期回报很好,这是一个很好的补充。 OP 绝对应该检查空数组作为快捷方式。也许我会改写我的主张,并且可以放心地说,最简洁的方法。
  • (当我第一次发布关于性能的声明时,Jeffrey 的回答有缺陷,所以我打了折扣)
【解决方案2】:

这是一种快速而肮脏的方法:循环遍历两个数组,外部循环填充内部循环。如果没有找到匹配项,则 $x 重新发送 0,并且该值将被添加到内部循环中。如果找到匹配项,则 $x 为 1,内循环将中断以继续外循环。

$a = [['a' => 10,'b' => 'g'], ['a' => 11,'b' => 'h']];
$b = [['a' => 1, 'b' => 'g'], ['a' => 2, 'b' => 'h'], ['a' => 3, 'b' => 'i']];

// now its fool proof.
function mergeData( $a, $b )
{
    if( empty( $a ) && empty( $b ) )
        return [];
    if( empty( $a ) )
        return $b;
    if( empty( $b ) )
        return $a;

    foreach( $b AS $i => $c ) {
        $x = 0;
        foreach( $a AS $ii => $d ) {
            if( $c['b'] == $d['b'] ) {
                $a[ $ii ]['a'] += $c['a'];
                $x             = 1;
                break;
            }
        }
        if( !$x )
            $a[] = $b[ $i ];
    }

    return $a;
}

输出

Array
(
    [0] => Array
        (
            [a] => 11
            [b] => g
        )

    [1] => Array
        (
            [a] => 13
            [b] => h
        )

    [2] => Array
        (
            [a] => 3
            [b] => i
        )

)

【讨论】:

  • $a 可以为空,在这种情况下输出会有所不同。
  • 如果 $a 为空,则不需要循环,因为 $b 就是答案。如前所述:这是一种快速而肮脏的方法,它有效,但没有检查是否为空等。
  • 对于投反对票的人,请提供理由(!)。这段代码运行正常,行为符合要求,是我能想到的最优化的代码。
【解决方案3】:

有点不同的方法

$array1 = [
    [
        'Contribution' => 10,
        'P_Name' => 'A'
    ],  
    [
        'Contribution' => 1500,
        'P_Name' => 'B'
    ]     
];
$array2 = [
    [
        'Contribution' => 200,
        'P_Name' => 'B'
    ],   
    [
        'Contribution' => 100,
        'P_Name' => 'C'
    ],   
];

$array3 = array_map(function($elem) use (&$array2){
    foreach($array2 as $i => &$a2){
        if($a2['P_Name'] == $elem['P_Name']){
            $a2['Contribution'] += $elem['Contribution'];
            return;
        }            
    }
    return $elem;
},$array1);

$array3 = array_merge(array_filter($array3),$array2);

print_r($array3);

输出:

Array
(
    [0] => Array
        (
            [Contribution] => 10
            [P_Name] => A
        )

    [1] => Array
        (
            [Contribution] => 1700
            [P_Name] => B
        )

    [2] => Array
        (
            [Contribution] => 100
            [P_Name] => C
        )
)

【讨论】:

    【解决方案4】:

    您可以使用array_reduce()array_map()array_sum()

    <?php
    
    function merge(array ...$sets)
    {
        /**
         * group contributions by name
         */
        $contributions = array_reduce(
            $sets,
            function (array $contributions, array $set) {
                foreach ($set as $element) {
                    $name = $element['P_Name'];
                    $contribution = $element['Contribution'];
    
                    if (!array_key_exists($name, $contributions)) {
                        $contributions[$name] = [];
                    }
    
                    $contributions[$name][] = $contribution;
    
                }
    
                return $contributions;
            },
            []
        );
    
        /**
         * normalize the array so we remove the name as key, and return a tuple of name and contribution, with the desired
         * structure
         */
        return array_values(array_map(function (array $contribution, $name) {
            return [
                'Contribution' => array_sum($contribution),
                'P_Name' => $name,
            ];
        }, $contributions, array_keys($contributions)));
    }
    
    $a = [
        [
            'Contribution' => 1000,
            'P_Name' => 'A',
        ],
        [
            'Contribution' => 1500,
            'P_Name' => 'B',
        ],
    ];
    
    $b = [
        [
            'Contribution' => 100,
            'P_Name' => 'A',
        ],
        [
            'Contribution' => 200,
            'P_Name' => 'B',
        ],
    ];
    
    $merged = merge($a, $b);
    
    var_dump($merged);
    

    注意因为使用了可变参数,所以可以将任意数量的数组传递给merge()。不过,至少需要 PHP 5.6。

    参考见:

    例如,请参阅:

    【讨论】:

      猜你喜欢
      • 2018-04-21
      • 2016-02-20
      • 2021-11-03
      • 1970-01-01
      • 2017-11-27
      • 2011-10-23
      • 1970-01-01
      • 2015-03-28
      • 2020-09-15
      相关资源
      最近更新 更多