【问题标题】:PHP merge arrays based on matching value of a given indexPHP根据给定索引的匹配值合并数组
【发布时间】:2019-06-12 09:58:03
【问题描述】:

我有两个这样的数组:

数组1

Array
(
    [0] => Array
        (
            [ID] => 101
            [Code] => 1075
            [Date] => 2012-03-03 17:13:12.433
        )

    [1] => Array
        (
            [ID] => 103
            [Code] => 175
            [Date] => 2012-09-05 20:30:02.217
        )

    [2] => Array
        (
            [ID] => 109
            [Code] => 178
            [Date] => 2012-07-05 20:30:02.217
        )

)

数组2

Array
(
    [0] => Array
        (
            [Amount] => 1234
            [ID] => 101
        )

    [1] => Array
        (
            [Amount] => 1342
            [ID] => 103
        )

    [2] => Array
        (
            [Amount] => 0
            [ID] => 0
        )

)

我使用此代码根据 ID 索引的匹配值将它们组合起来。

      $combined = array();
           foreach ($arr as $arrs) {
                   $comb = array('ID' => $arrs['ID'], 'Code' => $arrs['Code'],'Date' => $arrs['Date'],'Amount' => '');
                   foreach ($arr4 as $arr2) {
                       if ($arr2['ID'] == $arrs['ID']) {
                           $comb['Amount'] = $arr2['Amount'];
                           break;
                       }
                       else {
                        $comb['Amount'] = $arr2['Amount'];
                       }
                   }
               $combined[] = $comb;
           }
echo print_r($combined);

这是我从这段代码中得到的期望输出:

Array
(
    [0] => Array
        (
            [ID] => 101
            [Code] => 1075
            [Date] => 2012-03-03 17:13:12.433
            [Amount] => 1234
        )

    [1] => Array
        (
            [ID] => 103
            [Code] => 175
            [Date] => 2012-09-05 20:30:02.217
            [Amount] => 1342
        )

    [2] => Array
        (
            [ID] => 109
            [Code] => 178
            [Date] => 2012-07-05 20:30:02.217
            [Amount] => 0
        )

)

我想优化代码使得

$comb = array('ID' => $arrs['ID'], 'Code' => $arrs['Code'],'Date' => $arrs['Date'],'Amount' => ''); 

应该动态生成而不是硬编码。 而不是$comb['Amount'] = $arr2['Amount'];,我希望代码自动将所有其他字段添加到ID匹配的第一个数组中。

我如何做到这一点?

【问题讨论】:

  • 是否保证两个数组的元素数量相同,并且每个数组在另一个数组中都有一个匹配的 id?
  • @man0v 是的,两个数组都将具有相同数量的元素。但是每个数组可能没有匹配的 id,因为在数组 2 中没有 ID 109 的条目。我已经发布了我在问题中得到的输出。
  • 建议在另一个数组中缺少 id 时该怎么做。我们会忽略这些吗?还是我们将它们添加为单个 id?
  • 在这种情况下,请参阅输出的这一部分 [2] => Array ([ID] => 109 [Code] => 178 [Date] => 2012-07-05 20:30: 02.217 [Amount] => 0) 为 Array1 的 ID 添加数量 0
  • @AlivetoDie 不,两个数组中的元素可能没有相同的索引

标签: php arrays sorting


【解决方案1】:

除了ID之外,使其完全动态化的最简单解决方案,如下所示:

$arr2 = array_column($array2, "ID");

$finalArray = array();
foreach($array1 as $arr){
    $key = array_search($arr['ID'], $arr2);
    if($key ===false){
        $key = array_search(0, $arr2);
    }
    unset($array2[$key]['ID']);
    $finalArray[] =     array_merge($arr,$array2[$key]);
}

print_r($finalArray);

输出:- https://3v4l.org/1sDJs

【讨论】:

【解决方案2】:

先用ID作为key:

$arr1 = array_column($arr1, null, "ID");
$arr2 = array_column($arr2, null, "ID");

然后对key进行排序(解决原索引不一样的问题:

ksort($arr1);
ksort($arr2);

然后使用array_map作为:

$res = array_map('array_merge', $arr1, $arr2);

在末尾使用array_values 忽略ID 键。

如果您有另一个包含 ID 字段的数组,您可以在它们上使用相同的逻辑 - 请注意 array_map 可以获得超过 2 个输入数组...

参考:array_columnarray_maparray_mergeksort

现场示例:3v4l

已编辑

使用模板修复元素丢失的问题:

$keys = array_merge(array_keys($a[0]), array_keys($b[0]));
$template = array_combine($keys, array_fill(0, count($keys), null)); // create array of null for all keys
$a = array_column($a, null, "ID");
$b = array_column($b, null, "ID");
ksort($a);
ksort($b);


$res = array_map(function ($e1, $e2) use ($template){
    if ($e1 && $e2) return array_merge($e1, $e2); // if exist merge
    $e = $e1 ? $e1 : $e2; //get the exist element
    return array_replace ($template, $e); // add it
}, $a, $b);

请注意,此解决方案仅对 2 个数组有效 - 它可以概括,但我将其留给您

现场示例:3v4l

【讨论】:

  • 我有这个。但遗憾的是,这不是 OP 想要的:|。
  • 另外 OP 说在两个数组中的 id 可以在不同的索引处。
  • 是的,这并没有给出我提到的输出
  • 添加了 ksort 以避免不同的索引 - 并添加了实时示例 - 这在我看来是相同的输出,我错过了什么?
  • 是的 - 我确实尝试过更薄的版本 - 但是是的。我动态地做到了。 (我的示例仅包含 2 个元素和 2 个字段)
【解决方案3】:

我调整你的代码来做你需要的,这里是对我有用的完整代码:

<?php

$arr=Array(
     Array("ID" => 101, "Code" => 1075, "Date" => "2012-03-03 17:13:12.433"),
    Array("ID" => 103, "Code" => 175, "Date" => "2013-03-03 17:13:12.433"),
    Array("ID" => 109, "Code" => 178, "Date" => "2014-03-03 17:13:12.433")
);

$arr4 = Array(
    Array("ID" => 101, "Amount" => 1234),
    Array("ID" => 103, "Amount" => 1342),
    Array("ID" => 0, "Amount" => 0)
);

$combined = array();

foreach ($arr as $i => $arrs) {
    $combined['ID'][$i] = $arrs['ID'];
    $combined['Code'][$i] = $arrs['Code'];
    $combined['Date'][$i] = $arrs['Date'];

    foreach ($arr4 as $arr2) {
        if ($arr2['ID'] == $arrs['ID']) {
            $combined['Amount'][$i] = $arr2['Amount'];
            break;
        }
    }

    if (!isset($combined['Amount'][$i])) {
        $combined['Amount'][] = 0;
    }

}

echo print_r($combined);

?>

如果您出于不同原因需要进一步操作,我建议您阅读 array_keysarray_values 方法,它们非常有用。

【讨论】:

    【解决方案4】:
    $firstArray = [
        [
            'ID' => 101,
            'Code' => 1075,
            'Date' => '2012-03-03 17:13:12.433',
        ],
        [
            'ID' => 103,
            'Code' => 175,
            'Date' => '2012-09-05 20:30:02.217',
        ],
        [
            'ID' => 109,
            'Code' => 178,
            'Date' => '2012-07-05 20:30:02.217',
        ],
    ];
    
    $secondArray = [
        [
            'ID' => 101,
            'Amount' => 1234,
        ],
        [
            'ID' => 103,
            'Amount' => 1342,
        ],
        [
            'ID' => 0,
            'Amount' => 0,
        ],
    ];
    
    class DTO implements \Serializable
    {
        /** @var int */
        private $id;
    
        /** @var int */
        private $code;
    
        /** @var string */
        private $date;
    
        /** @var int */
        private $amount = 0;
    
        /**
         * {@inheritDoc}
         */
        public function serialize()
        {
            return [
                'ID' => $this->id,
                'Code' => $this->code,
                'Date' => $this->date,
                'Amount' => $this->amount,
            ];
        }
    
        /**
         * {@inheritDoc}
         *
         * @param array $serialized
         */
        public function unserialize($serialized): self
        {
            $this->id = $serialized['ID'];
            $this->code = $serialized['Code'];
            $this->date = $serialized['Date'];
            $this->amount = $serialized['Amount'] ?? 0;
    
            return $this;
        }
    }
    
    $thirdArray = [];
    foreach ($secondArray as $item) {
        $id = $item['ID'];
        unset($item['ID']);
        $thirdArray[$id] = $item;
    }
    
    $thirdArrayKeys = array_keys($thirdArray);
    foreach ($firstArray as &$item) {
        $id = $item['ID'];
        $dto = new DTO();
        $dto->unserialize($item);
        if (in_array($id, $thirdArrayKeys)) {
            $dto = $dto->unserialize(array_merge($item, $thirdArray[$id]));
        }
    
        $item = $dto->serialize();
    }
    

    http://sandbox.onlinephpfunctions.com/code/ee72a1c89782f4eef25a1143816f237ca6af129c

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    相关资源
    最近更新 更多