首页 > 解决方案 > 如何在 PHP 中的两个数组中查找和删除相同的值?

问题描述

我在数组中有两个数据,我需要在两个数组中找到相同的值,然后在第二个数组中删除相同的值。但是第二个数组中有一个 JSON 值

这是数据:

$arr1 = [
       99 => [
           "number" => [1,3]
          ],
       88 => [
           "number" => [12,13,21]
           ]
    ];

$arr2 = [
           ["a"=>"01","b"=> '["01", "02", "03", "04"]'], 
           ["a"=>"02","b"=> '["11", "12", "13"]'],
           ["a"=>"03","b"=> '["21", "22", "23"]']
    ];

我试过的:

foreach($arr1 as $val1){
foreach($val1['number'] as $number){
    foreach($arr2 as $key => $val2){
        if(in_array($number,json_decode($val2['b']))){
            unset($arr2[$key ]);
        }
    }
}
}

我希望得到输出:

 $arr2= [
    {"a":"01","b": ["02", "04"]}, 
    {"a":"02","b": ["11"]},
    {"a":"03","b": ["22", "23"]}
 ]

但我得到的实际输出是:

array(0) { }

标签: phpjson

解决方案


给你,我为你做的。

$arr1 = [
       99 => [
           "number" => [1,3]
          ],
       88 => [
           "number" => [12,13,21]
           ]
    ];

$arr2 = [
           ["a"=>"01","b"=> '["01", "02", "03", "04"]'], 
           ["a"=>"02","b"=> '["11", "12", "13"]'],
           ["a"=>"03","b"=> '["21", "22", "23"]']
    ];

$numbers = preg_replace('/^(\d)$/', '0\1', array_merge(...array_column($arr1, 'number')));


array_walk($arr2, function(&$item)use($numbers){
        $item['b'] = array_diff(json_decode($item['b'], true),$numbers);
});


print_r($arr2);

输出

Array
(
    [0] => Array
        (
            [a] => 01
            [b] => Array
                (
                    [1] => 02
                    [3] => 04
                )

        )

    [1] => Array
        (
            [a] => 02
            [b] => Array
                (
                    [0] => 11
                )

        )

    [2] => Array
        (
            [a] => 03
            [b] => Array
                (
                    [1] => 22
                    [2] => 23
                )

        )

)

沙盒

这个怎么运作。

每当您发现自己需要将一个多维数组与另一个进行比较时,请记住array_column。这允许您从嵌套数组中拉出一列。这样做是简化其中一个数组并使事情变得更容易一些。

因此,让我们逐个函数地思考上面的代码(按照它们被调用的顺序):

array_column($arr1, 'number');
//Output: [[1,3],[12,13,21]]

这不是我们所需要的,我们可以使用array_mergevariadic ( PHP >= 5.6) 或可变长度参数进一步简化它。其中...有这个效果:

 array_merge([1,3],[12,13,21]); //each nested array is a new argument
 //Output: [1,3,12,13,21]

现在我们有了一些简单的东西可以使用,但仍然存在一个问题。这是另一个列表中的值是带有前导的字符串,0s并且在您的预期输出中您保留这些。所以要解决这个问题,我们可以使用preg_replace

preg_replace('/^(\d)$/', '0\1',[1,3,12,13,21])
//Output: ['01','03','12','13','21']

//non regex methods
//array_map(function($v){return strlen($v)>1?$v:"0$v";},[1,3,12,13,21])
//array_map(function($v){return str_pad($v,2,'0',STR_PAD_LEFT);},[1,3,12,13,21])

正则表达式^(\d)$只是匹配只有1数字的元素。然后我们捕获它并在替换中使用它0\1。将\1我们捕获的那个号码转移到那个“替换”字符串中。0这有效地为带有数字的项目添加了前导1,这正是我们所需要的。有一些非正则表达式方法可以做到这一点,但它们都不是“漂亮”,请参见上面的非正则表达式示例。

我假设json_decode不需要介绍。

然后我们简单地遍历它们(在本例中为array_walk),并使用array_diff比较两个数组。这仅返回 array1 中不在 array2 中的项目。所以为此

 //loop1
 array_diff(["01", "02", "03", "04"],['01','03','12','13','21']);
 //Output: ["02", "04"]

 //loop2
 array_diff(["11", "12", "13"],['01','03','12','13','21']);
 //Output: ["11"]

 //loop3
 array_diff(["21", "22", "23"],['01','03','12','13','21']); 
 //Output: ["22", "23"]

然后因为在我们的闭包中通过引用进行更新 function(&$item),所以我们都完成了。

是的,那很有趣!不幸的是,我没有看到一种方法可以做到这一点1,但是我所拥有的基本上是2线条,所以这还不错......

希望这有助于解释它。

更新

我撒谎了,我想出了如何1在行中做到这一点(165字节):

  array_walk($arr2,function(&$i,$k,$n){$i['b']=array_diff(json_decode($i['b'],true),$n);},preg_filter('/^(\d)$/','0\1',array_merge(...array_column($arr1,'number'))));

为此(我记得),您可以将其他参数传递给array_map我,这就是我所做的。这避免了use语句的分配问题。就像任何函数一样,您无法设置作为另一个函数调用结果的默认值。

 //for example this doesn't work
 function(&$item)use($numbers = preg_replace(...)){ ... }

但这确实($n在这种情况下是额外的论点):

 array_walk($arr2,function(&$i,$k,$n){....},preg_replace(...));

沙盒

夏天的

本质上,我正在做的是获取其中一个数组并使其格式与我们想要比较的格式相同。这样一来,我们就简化了问题,而不是仅仅向它抛出大量代码。降低复杂性总是更好,如果你不知道这些功能在亲密层面上做了什么,那就是“复杂”。但我确实知道这一点,所以对我来说阅读并不难。

干杯!


推荐阅读