从重新使用的数组中删除先前迭代的数据

Remove previous iteration's data from re-used array

我有两个数组,$array1$array2$array2 是数组的数组。对于 $array2 的每个子数组,我想打印 $array1,但要打印其他条目,这些条目取决于 $array2 子数组是否具有键 "a""c",值为 1。我的代码在每个循环中打印 $array1,但在 $array1 中还有我没有预料到的后续迭代的其他条目。为什么我会收到这些条目,我该如何防止它们?

示例代码:

$array1 = array(
    "service" => "coding",
    "data" => array(
        "ITEM" => array(
            array(
                "CODE" => "9999", //STANDARD
                "QUANTITY" => 1
            ),
        )
    )
);

$array2 = array(
    array(
        "a" => "1",
        "b" => "1",
        "c" => "1",
        "d" => "1",
    ),
    array(
        "cancel" => "1",
        "a" => "1",
        "b" => "",
        "c" => "",
        "d" => "1",
    ),
    array(
        "cancel" => "1",
        "a" => "",
        "b" => "1",
        "c" => "1",
        "d" => "",
    ),
);

for ($i = 0; $i < count($array2); $i++) {
    foreach ($array2[$i] as $key => $value) {
        if($key == 'a' && $value == 1){
            array_push($array1['data']['ITEM'],
                array('SOMETHING' =>  'this_is_a',
                    'ELSE' => "1"
                )
            );
        }
        if($key == 'c' && $value == 1){
            array_push($array1['data']['ITEM'],
                array('SOMETHING' =>  'this_is_c',
                    'ELSE' => "1"
                )
            );
        }
    }

    echo "Loop #$i result:\n";    
    var_export($array1);
    echo "\n";
}

您可以将上述代码作为 PHP Sandbox snippet.

进行测试

实际结果是:

Loop #0 result:
array (
  'service' => 'coding',
  'data' => 
  array (
    'ITEM' => 
    array (
      0 => 
      array (
        'CODE' => '9999',
        'QUANTITY' => 1,
      ),
      1 => 
      array (
        'SOMETHING' => 'this_is_a',
        'ELSE' => '1',
      ),
      2 => 
      array (
        'SOMETHING' => 'this_is_c',
        'ELSE' => '1',
      ),
    ),
  ),
)
Loop #1 result:
array (
  'service' => 'coding',
  'data' => 
  array (
    'ITEM' => 
    array (
      0 => 
      array (
        'CODE' => '9999',
        'QUANTITY' => 1,
      ),
      1 => 
      array (
        'SOMETHING' => 'this_is_a',
        'ELSE' => '1',
      ),
      2 => 
      array (
        'SOMETHING' => 'this_is_c',
        'ELSE' => '1',
      ),
      3 => 
      array (
        'SOMETHING' => 'this_is_a',
        'ELSE' => '1',
      ),
    ),
  ),
)
Loop #2 result:
array (
  'service' => 'coding',
  'data' => 
  array (
    'ITEM' => 
    array (
      0 => 
      array (
        'CODE' => '9999',
        'QUANTITY' => 1,
      ),
      1 => 
      array (
        'SOMETHING' => 'this_is_a',
        'ELSE' => '1',
      ),
      2 => 
      array (
        'SOMETHING' => 'this_is_c',
        'ELSE' => '1',
      ),
      3 => 
      array (
        'SOMETHING' => 'this_is_a',
        'ELSE' => '1',
      ),
      4 => 
      array (
        'SOMETHING' => 'this_is_c',
        'ELSE' => '1',
      ),
    ),
  ),
)

循环 #0 结果正确,但后面的循环在 $array1['data']['ITEM'] 中有其他条目。期望的结果:

Loop #0 result:
array (
  'service' => coding
  'data' => array (
    'ITEM' => array (
      0 => array (
        'CODE' => 9999
        'QUANTITY' => 1
      )
      1 => array (
        'SOMETHING' => 'this_is_a'
        'ELSE' => 1
      )
      2 => array (
        'SOMETHING' => 'this_is_c'
        'ELSE' => 1
      )
    )
  )
)
Loop #1 result:
array (
  'service' => coding
  'data' => array (
    'ITEM' => array (
      0 => array (
        'CODE' => 9999
        'QUANTITY' => 1
      )
      1 => array (
        'SOMETHING' => 'this_is_a'
        'ELSE' => 1
      )
    )
  )
)
Loop #2 result:
array (
  'service' => coding
  'data' => array (
    'ITEM' => array (
      0 => array (
        'CODE' => 9999
        'QUANTITY' => 1
      )
      1 => array (
        'SOMETHING' => 'this_is_c'
        'ELSE' => 1
      )
    )
  )
)

您可以使用 array_map 循环遍历第二个数组,并且仅在当前迭代具有名为 a 的键且其值为 [= 时才推送到第一个数组的 ['data']['ITEM'] 14=].

$arr1 = [
    'service' => 'coding',
    'data' => [
        'ITEM' => [
            [
                'CODE' => '9999',
                'QUANTITY' => 1
            ]
        ]
    ]
];
$arr2 = [
    [
        'a' => '1',
        'b' => '1',
        'c' => '1',
        'd' => '1',
    ],
    [
        'cancel' => '1',
        'a' => '1',
        'b' => '',
        'c' => '',
        'd' => '1',
    ],
    [
        'cancel' => '1',
        'a' => '',
        'b' => '1',
        'c' => '1',
        'd' => '',
    ],
];

// loop through the second array ($arr2)
// the "use" is very important here as it let's the callback function to access $arr1 variable
$finalArr = array_map(function ($el) use ($arr1) {
    // if in the current iteration a kley named "a" and its value is "1" is found then push it to the first array's ['data']['ITEM'] key.
    // $arr1 here is passed by value so the real array won't be channged, we're, more or less, working with copy of $arr1 in the function.
    isset($el['a']) && $el['a'] == 1 && ($arr1['data']['ITEM'][] = [
        'something' => 'This is a', // tried to keep same output as yours
        'else' => $el['a'] // tried to keep same output as yours
    ]);
    // for "c" key
    isset($el['c']) && $el['c'] == 1 && ($arr1['data']['ITEM'][] = [
        'something' => 'This is c', // tried to keep same output as yours
        'else' => $el['c'] // tried to keep same output as yours
    ]);
    // return the $arr1 copy regardless of whether we pushed "a" key or not.
    return $arr1;
}, $arr2);

// print the resulting array
print_r($finalArr);

结果(样本数据):

array(
  0 => array(
    'service' => 'coding',
    'data' => array(
      'ITEM' => array(
        0 => array(
          'CODE' => '9999',
          'QUANTITY' => 1,
        ),
        1 => array(
          'something' => 'This is a',
          'else' => '1',
        ),
        2 => array(
          'something' => 'This is c',
          'else' => '1',
        ),
      ),
    ),
  ),
  1 => array(
    'service' => 'coding',
    'data' => array(
      'ITEM' => array(
        0 => array(
          'CODE' => '9999',
          'QUANTITY' => 1,
        ),
        1 => array(
          'something' => 'This is a',
          'else' => '1',
        ),
      ),
    ),
  ),
  2 => array(
    'service' => 'coding',
    'data' => array(
      'ITEM' => array(
        0 => array(
          'CODE' => '9999',
          'QUANTITY' => 1,
        ),
        1 => array(
          'something' => 'This is c',
          'else' => '1',
        ),
      ),
    ),
  ),
)

您可以在 PHP 手册中了解有关 callback functions(匿名函数)的更多信息。

您不会在每次迭代之间将 $array1['data']['ITEM'] 返回到其原始状态。只需在 for()foreach() 之间写下以下内容即可。

$array1['data']['ITEM'] = array_slice($array1['data']['ITEM'], 0, 1);

因为数组键必须是唯一的,所以您不需要遍历所有元素来查看 ac 是否存在——这将花费不必要的循环。

此外,我发现数组解构是一个很好的选择,可以隔离您寻求的仅有的两个值。

我可能会推荐这个更简单、更直观的片段:(Demo)

foreach ($array2 as $i => ['a' => $a, 'c' => $c]) {
    $temp = $array1;
    if($a == 1) {
        $temp['data']['ITEM'][] = [
            'SOMETHING' => 'this_is_a',
            'ELSE' => '1'
        ];
    }
    if ($c == 1) {
        $temp['data']['ITEM'][] = [
            'SOMETHING' => 'this_is_c',
            'ELSE' => '1'
        ];
    }

    echo "Loop #$i result:\n";    
    var_export($temp);
    echo "\n";
}

 

出现意外条目是因为 $array1 在每次迭代中都被修改(具体来说,由 array_push 修改)。为防止这种情况,每次迭代都必须对 $array1 的不同副本进行操作。由于 variable assignment and argument passing will each copy an array, either could be used. Similar to argument passing, closures 可以从外部范围继承(注意:不是 OOP 意义上的)变量,绑定到它们的值(这将复制一个数组),为解决方案提供第三个潜在基础。

需要最少编辑量的修复方法是在循环开始时将 $array1 分配给另一个变量,并在循环的其余部分用此变量替换 $array1

for ($i = 0; $i < count($array2); $i++) {
    $result = $array1;
    // ...

或者,通过将循环体移动到函数中,$array1 成为函数体中的副本:

function process(array $options, array $output) {
    // Ensure entries to test are present:
    $options += ['a' => NULL, 'c' => NULL];
    /* As an alternative to the above, if entries should be added 
     * to $output whenever 'a' or 'c' has a truthy value, 
     * `! empty(...)` could be used instead of the `... == 1`
     * tests below.
     */

    if ($options['a'] == 1) {
        $output['data']['ITEM'][] = [
            'SOMETHING' =>  'this_is_a',
            'ELSE' => 1,
        ];
    }
    if ($options['c'] == 1) {
        $output['data']['ITEM'][] = [
            'SOMETHING' =>  'this_is_c',
            'ELSE' => 1,
        ];
    }
    return $output;
}

foreach ($array2 as $i => $subarray) {
    echo "// Loop #$i result:";
    var_export( process($subarray, $array1) );
    echo ";\n";
}

作为第三种方法,您可以应用 array_map to $array2, as is done by 。为了进行比较,可以将前面的 foreach 循环替换为对 array_map:

的调用
var_export(
    array_map(function (array $subarray) use ($array1) {
            return process($subarray, $array1); 
        }, $array2)
);

或者,使用 arrow function(自动使用外部作用域中的变量):

var_export(
    array_map(
        fn (array $subarray) => process($subarray, $array1),
        $array2
)   );

请注意,对于不会被修改(或修改无关紧要)的数组,您可以 pass them by reference(或在闭包中通过引用绑定)以避免复制它们的开销。

function process(array &$options, array $output) {
    // ...