Search code examples
phparraysreplacestr-replacearray-key

How to remove/replace certain characters from both keys and values in an array?


My goal is to remove a group of characters from a one dimensional array's keys and another group of characters from that same array's values. Example:

$arr = [
  'a' => 'Letter A!',
  '`b`' => 'Letter B w/quotes...',
  ' c ' => 'Letter C w/spaces?',
  ' -_-`d`- _ - ' => 'Letter D w/all?!...'
];
$invalid_keys_chars = ['`',' ','_','-'];
$invalid_vals_chars = ['!','?','.'];

// GOAL: looking for something like this function
array_del_invalid($arr, $invalid_keys_chars, $invalid_vals_chars));
var_export($arr);
// ---> output
// array (
//   'a' => 'Letter A',
//   'b' => 'Letter B w/quotes',
//   'c' => 'Letter C w/spaces',
//   'd' => 'Letter D w/all'
// )

I looked first into common PHP functions:

  • array_walk example: allows the replacement of values by reference, but if I also pass the key by reference in the callback parameters the same doesn't happen;
  • array_replace: keys are also not modified;
  • array_map example: constructing a copy of an array, but previous treatment of array_keys($arr) is necessary.

So my goal is to perform all the replacements in one go, avoiding reusing PHP functions that loop several times the array.

I placed an answer on this same thread with my attempt, which is working, but I couldn't figure out a way to avoid unset($arr[$invalid_key]) (is there another way to "change" the key itself without removing it?) or doing only one assignment if both key and value strings need replacement.

Is there already a PHP function that does this? I.e. single-loop, few conditions, minimum replacements and overall more efficient? If not, how can I improve mine?


Solution

  • No, there is no way in PHP you can modify an array key by reference. You can only add and remove keys.

    Even array_change_key_case will create a new array instead of modifying the original.

    You can create a new array in your function and return the new array. You can then overwrite your original array variable with the clean version.

    <?php
    function deleteInvalid($dirty, $ikc = [], $ivc = []) {
        $clean = [];
        foreach ($dirty as $key => $val) {
            $cKey = str_replace($ikc, '', $key);
            $cVal = str_replace($ivc, '', $val);
            $clean[$cKey] = $cVal;
        }
        return $clean;
    }
    
    $dirty = deleteInvalid($dirty);
    var_dump($dirty);
    

    You don't need to test the changes of the values after str_replace as it'll be the same if it was not changed. Unless of course your array contains more than strings... in which case you should test the type of value before modifying.

    <?php
    if (is_string($val)) {
        // do something with the string.
    }