递归地从多维数组中删除特定的键

时间:2021-08-13 10:45:24

I am trying to create a function to remove keys from a dynamic multidimensional array, i need to give:

我正在尝试创建一个从动态多维数组中删除键的函数,我需要给出:

removeByIndex(['hello', 'my', 'world']);

And then the function needs to do this:

然后函数需要这样做:

unset($array['hello']['my']['world']);

The number of indexes are dynamic, example:

索引的数量是动态的,例如:

removeByIndex(['hello', 'my']); // Do: unset($array['hello']['my']);
removeByIndex(['hello']); // Do: unset($array['hello']);

I tried to use some foreach loops, but i didn't find a solution yet.

我尝试使用一些foreach循环,但是我还没有找到一个解决方案。

Any help will be welcome.

欢迎任何帮助。

3 个解决方案

#1


2  

No need for eval() with a little bit of referencing.

不需要使用带一点引用的eval()。

/**
 * Remove index from multi-dimensional array.
 *
 * @param array $array
 *   The array to remove the index from.
 * @param array $indices
 *   Indexed array containing the indices chain up to the index that should be
 *   removed.
 * @return
 *   The array with the index removed.
 * @throws \InvalidArgumentException
 *   If the index does not exist within the array.
 */
function removeByIndex(array $array, array $indices) {
  // Create a reference to the original array.
  $a =& $array;

  // Count all passed indices, remove one because arrays are zero based.
  $c = count($indices) - 1;

  // Iterate over all passed indices.
  for ($i = 0; $i <= $c; ++$i) {
    // Make sure the index to go down for deletion actually exists.
    if (array_key_exists($indices[$i], $a)) {
      // This is the target if we reached the last index that was passed.
      if ($i === $c) {
        unset($a[$indices[$i]]);
      }
      // Make sure we have an array to go further down.
      elseif (is_array($a[$indices[$i]])) {
        $a =& $a[$indices[$i]];
      }
      // Index does not exist since there is no array to go down any further.
      else {
        throw new \InvalidArgumentException("{$indices[$i]} does not exist.");
      }
    }
    // Index does not exist, error.
    else {
      throw new \InvalidArgumentException("{$indices[$i]} does not exist.");
    }
  }

  return $array;
}

print_r(removeByIndex(
  [ "test1" => [ "test2" => [ "test3" => "test" ] ], "test4" => "test" ],
  [ "test1", "test2", "test3" ]
));

Since I mentioned it in the comments, one could (micro-)optimize the function, but I advice against it, since it is less readable and might confuse some programmers.

由于我在评论中提到了它,我们可以(微)优化函数,但我建议不要这样做,因为它可读性较差,可能会让一些程序员感到困惑。

<?php

function removeByIndex(array $array, array $indices) {
  $a =& $array;
  $c = count($indices) - 1;
  $i = 0;
  do {
    if (array_key_exists($indices[$i], $a)) {
      if ($i === $c) {
        unset($a[$indices[$i]]);
        return $array;
      }
      elseif (is_array($a[$indices[$i]])) {
        $a =& $a[$indices[$i]];
      }
      else break;
    }
    else break;
  }
  while (++$i);
  throw new \InvalidArgumentException("{$indices[$i]} does not exist.");
}

#2


1  

Based on the briliant @Fleshgrinder answer, i am using this final version:

基于briliant @ grinder answer,我正在使用这个最终版本:

function removeByIndex($vars, $indexes) {
    if ( ! is_array($indexes)) {
        throw new \Exception('Array expected');
    }

    $array = & $vars;

    $qtd_indexes = count($indexes);

    for ($i = 0; $i < $qtd_indexes; $i++) {
        if ( ! array_key_exists($indexes[$i], $array)) {
          throw new \Exception($indexes[$i] . " doesn't exist");
        }

        // Check if it is the target entry
        if ($i === $qtd_indexes - 1) {
            unset($array[$indexes[$i]]);
        } elseif (is_array($array[$indexes[$i]])) { // Check if exists one more level
            $array = & $array[$indexes[$i]];
        } else {
            // If it isn't the target and it isn't an array, throw exception
            throw new \Exception("Content of '" . $indexes[$i] . "' isn't an array");
        }
    }

    return $vars;
}

#3


1  

I was researched for a couple of hours for this solution, nowhere found an optimal solution. so, i wrote it by myself

我为这个解决方案研究了几个小时,没有找到一个最优解。我自己写的

function allow_keys($arr, $keys)
    {
        $saved = [];

        foreach ($keys as $key => $value) {
            if (is_int($key) || is_int($value)) {
                $keysKey = $value;
            } else {
                $keysKey = $key;
            }
            if (isset($arr[$keysKey])) {

                $saved[$keysKey] = $arr[$keysKey];
                if (is_array($value)) {

                    $saved[$keysKey] = allow_keys($saved[$keysKey], $keys[$keysKey]);
                }
            }
        }
        return $saved;
    }

use: example

用途:示例

$array = [
        'key1' => 'kw',
        'loaa'=> ['looo'],
        'k'    => [
            'prope' => [
                'prop'  => ['proo', 'prot', 'loolooo', 'de'],
                'prop2' => ['hun' => 'lu'],
            ],
            'prop1' => [

            ],
        ],
    ];

call: example

电话:示例

allow_keys($array, ['key1', 'k' => ['prope' => ['prop' => [0, 1], 'prop2']]])

output:

输出:

Array ( [key1] => kw [k] => Array ( [prope] => Array ( [prop] => Array ( [0] => proo [1] => prot ) [prop2] => Array ( [hun] => lu ) ) ) ) 

so you get only needed keys from the multidimensional array. it is not limited only for "multidimensional", you can use it by passing an array like

所以你只从多维数组中得到需要的键。它不仅仅局限于“多维”,你可以通过一个数组来使用它。

['key1', 'loaa']

output you get:

输出得到:

Array ( [key1] => kw [loaa] => Array ( [0] => looo ) )

i'm writing it here for reason that this topic is one of the first when you type on google

我写这篇文章的原因是这个主题是你在谷歌上输入的第一个主题

recursive remove keys multidimensional php

递归删除多维php中的键

hope someone helps this one, as i searched a lot, and nothing found. cheers!

希望有人能帮助这个,因为我找了很多,没有找到。干杯!

#1


2  

No need for eval() with a little bit of referencing.

不需要使用带一点引用的eval()。

/**
 * Remove index from multi-dimensional array.
 *
 * @param array $array
 *   The array to remove the index from.
 * @param array $indices
 *   Indexed array containing the indices chain up to the index that should be
 *   removed.
 * @return
 *   The array with the index removed.
 * @throws \InvalidArgumentException
 *   If the index does not exist within the array.
 */
function removeByIndex(array $array, array $indices) {
  // Create a reference to the original array.
  $a =& $array;

  // Count all passed indices, remove one because arrays are zero based.
  $c = count($indices) - 1;

  // Iterate over all passed indices.
  for ($i = 0; $i <= $c; ++$i) {
    // Make sure the index to go down for deletion actually exists.
    if (array_key_exists($indices[$i], $a)) {
      // This is the target if we reached the last index that was passed.
      if ($i === $c) {
        unset($a[$indices[$i]]);
      }
      // Make sure we have an array to go further down.
      elseif (is_array($a[$indices[$i]])) {
        $a =& $a[$indices[$i]];
      }
      // Index does not exist since there is no array to go down any further.
      else {
        throw new \InvalidArgumentException("{$indices[$i]} does not exist.");
      }
    }
    // Index does not exist, error.
    else {
      throw new \InvalidArgumentException("{$indices[$i]} does not exist.");
    }
  }

  return $array;
}

print_r(removeByIndex(
  [ "test1" => [ "test2" => [ "test3" => "test" ] ], "test4" => "test" ],
  [ "test1", "test2", "test3" ]
));

Since I mentioned it in the comments, one could (micro-)optimize the function, but I advice against it, since it is less readable and might confuse some programmers.

由于我在评论中提到了它,我们可以(微)优化函数,但我建议不要这样做,因为它可读性较差,可能会让一些程序员感到困惑。

<?php

function removeByIndex(array $array, array $indices) {
  $a =& $array;
  $c = count($indices) - 1;
  $i = 0;
  do {
    if (array_key_exists($indices[$i], $a)) {
      if ($i === $c) {
        unset($a[$indices[$i]]);
        return $array;
      }
      elseif (is_array($a[$indices[$i]])) {
        $a =& $a[$indices[$i]];
      }
      else break;
    }
    else break;
  }
  while (++$i);
  throw new \InvalidArgumentException("{$indices[$i]} does not exist.");
}

#2


1  

Based on the briliant @Fleshgrinder answer, i am using this final version:

基于briliant @ grinder answer,我正在使用这个最终版本:

function removeByIndex($vars, $indexes) {
    if ( ! is_array($indexes)) {
        throw new \Exception('Array expected');
    }

    $array = & $vars;

    $qtd_indexes = count($indexes);

    for ($i = 0; $i < $qtd_indexes; $i++) {
        if ( ! array_key_exists($indexes[$i], $array)) {
          throw new \Exception($indexes[$i] . " doesn't exist");
        }

        // Check if it is the target entry
        if ($i === $qtd_indexes - 1) {
            unset($array[$indexes[$i]]);
        } elseif (is_array($array[$indexes[$i]])) { // Check if exists one more level
            $array = & $array[$indexes[$i]];
        } else {
            // If it isn't the target and it isn't an array, throw exception
            throw new \Exception("Content of '" . $indexes[$i] . "' isn't an array");
        }
    }

    return $vars;
}

#3


1  

I was researched for a couple of hours for this solution, nowhere found an optimal solution. so, i wrote it by myself

我为这个解决方案研究了几个小时,没有找到一个最优解。我自己写的

function allow_keys($arr, $keys)
    {
        $saved = [];

        foreach ($keys as $key => $value) {
            if (is_int($key) || is_int($value)) {
                $keysKey = $value;
            } else {
                $keysKey = $key;
            }
            if (isset($arr[$keysKey])) {

                $saved[$keysKey] = $arr[$keysKey];
                if (is_array($value)) {

                    $saved[$keysKey] = allow_keys($saved[$keysKey], $keys[$keysKey]);
                }
            }
        }
        return $saved;
    }

use: example

用途:示例

$array = [
        'key1' => 'kw',
        'loaa'=> ['looo'],
        'k'    => [
            'prope' => [
                'prop'  => ['proo', 'prot', 'loolooo', 'de'],
                'prop2' => ['hun' => 'lu'],
            ],
            'prop1' => [

            ],
        ],
    ];

call: example

电话:示例

allow_keys($array, ['key1', 'k' => ['prope' => ['prop' => [0, 1], 'prop2']]])

output:

输出:

Array ( [key1] => kw [k] => Array ( [prope] => Array ( [prop] => Array ( [0] => proo [1] => prot ) [prop2] => Array ( [hun] => lu ) ) ) ) 

so you get only needed keys from the multidimensional array. it is not limited only for "multidimensional", you can use it by passing an array like

所以你只从多维数组中得到需要的键。它不仅仅局限于“多维”,你可以通过一个数组来使用它。

['key1', 'loaa']

output you get:

输出得到:

Array ( [key1] => kw [loaa] => Array ( [0] => looo ) )

i'm writing it here for reason that this topic is one of the first when you type on google

我写这篇文章的原因是这个主题是你在谷歌上输入的第一个主题

recursive remove keys multidimensional php

递归删除多维php中的键

hope someone helps this one, as i searched a lot, and nothing found. cheers!

希望有人能帮助这个,因为我找了很多,没有找到。干杯!