PHP: Как использовать array_filter() для фильтрации ключей массива?

Функция обратного вызова в array_filter() передает только значения массива, а не ключи.

Если у меня есть:

$my_array = array("foo" => 1, "hello" => "world");

$allowed = array("foo", "bar");

Какой лучший способ удалить все ключи в $my_array, которые не входят в массив $allowed?

Требуемый вывод:

$my_array = array("foo" => 1);

Ответ 1

В PHP 5.6 был введен третий параметр array_filter(), flag, который можно установить на ARRAY_FILTER_USE_KEY для фильтрации по ключу вместо значения:

$my_array = ['foo' => 1, 'hello' => 'world'];
$allowed  = ['foo', 'bar'];
$filtered = array_filter(
    $my_array,
    function ($key) use ($allowed) {
        return in_array($key, $allowed);
    },
    ARRAY_FILTER_USE_KEY
);

Очевидно, что это не так элегантно, как array_intersect_key($my_array, array_flip($allowed)), но он предлагает дополнительную гибкость при выполнении произвольного теста против ключа, например. $allowed может содержать шаблоны регулярных выражений вместо простых строк.

Вы также можете использовать ARRAY_FILTER_USE_BOTH, чтобы иметь как значение, так и ключ, переданный вашей функции фильтра. Здесь надуманный пример, основанный на первом, но обратите внимание, что я бы не рекомендовал правила фильтрации кодирования, используя $allowed следующим образом:

$my_array = ['foo' => 1, 'bar' => 'baz', 'hello' => 'wld'];
$allowed  = ['foo' => true, 'bar' => true, 'hello' => 'world'];
$filtered = array_filter(
    $my_array,
    function ($val, $key) use ($allowed) { // N.b. $val, $key not $key, $val
        return isset($allowed[$key]) && (
            $allowed[$key] === true || $allowed[$key] === $val
        );
    },
    ARRAY_FILTER_USE_BOTH
); // ['foo' => 1, 'bar' => 'baz']

Ответ 2

С array_intersect_key и array_flip:

var_dump(array_intersect_key($my_array, array_flip($allowed)));

array(1) {
  ["foo"]=>
  int(1)
}

Ответ 3

Мне нужно было сделать то же самое, но с более сложным array_filter на клавишах.

Вот как я это сделал, используя аналогичный метод.

// Filter out array elements with keys shorter than 4 characters
$a = array(
  0      => "val 0", 
  "one"  => "val one", 
  "two"  => "val two", 
  "three"=> "val three", 
  "four" => "val four", 
  "five" => "val five", 
  "6"    => "val 6"
); 

$f = array_filter(array_keys($a), function ($k){ return strlen($k)>=4; }); 
$b = array_intersect_key($a, array_flip($f));
print_r($b);

Это выводит результат:

Array
(
    [three] => val three
    [four] => val four
    [five] => val five
)

Ответ 4

Вот более гибкое решение, использующее закрытие:

$my_array = array("foo" => 1, "hello" => "world");
$allowed = array("foo", "bar");
$result = array_flip(array_filter(array_flip($my_array), function ($key) use ($allowed)
{
    return in_array($key, $allowed);
}));
var_dump($result);

Выходы:

array(1) {
  'foo' =>
  int(1)
}

Таким образом, в функции вы можете выполнять другие специальные тесты.

Ответ 5

Если вы ищете метод фильтрации массива по строке, входящей в ключи, вы можете использовать:

$mArray=array('foo'=>'bar','foo2'=>'bar2','fooToo'=>'bar3','baz'=>'nope');
$mSearch='foo';
$allowed=array_filter(
    array_keys($mArray),
    function($key) use ($mSearch){
        return stristr($key,$mSearch);
    });
$mResult=array_intersect_key($mArray,array_flip($allowed));

Результат print_r($mResult) равен

Array ( [foo] => bar [foo2] => bar2 [fooToo] => bar3 )

Адаптация этого ответа, который поддерживает регулярные выражения

function array_preg_filter_keys($arr, $regexp) {
  $keys = array_keys($arr);
  $match = array_filter($keys, function($k) use($regexp) {
    return preg_match($regexp, $k) === 1;
  });
  return array_intersect_key($arr, array_flip($match));
}

$mArray = array('foo'=>'yes', 'foo2'=>'yes', 'FooToo'=>'yes', 'baz'=>'nope');

print_r(array_preg_filter_keys($mArray, "/^foo/i"));

Выход

Array
(
    [foo] => yes
    [foo2] => yes
    [FooToo] => yes
)

Ответ 6

Как получить текущий ключ массива при использовании array_filter

Независимо от того, как мне нравится решение Vincent для проблемы Maček, оно фактически не использует array_filter. Если вы пришли сюда из поисковой системы, возможно, вы ищете что-то вроде этого (PHP >= 5.3):

$array = ['apple' => 'red', 'pear' => 'green'];
reset($array); // Unimportant here, but make sure your array is reset

$apples = array_filter($array, function($color) use ($&array) {
  $key = key($array);
  next($array); // advance array pointer

  return key($array) === 'apple';
}

Он передает массив, который вы фильтруете, в качестве ссылки на обратный вызов. Поскольку array_filter не традиционно перебирает массив, увеличивая его внутренний внутренний указатель, вы должны заранее его продвигать.

Важно то, что вам нужно убедиться, что ваш массив reset, иначе вы можете начать прямо посередине.

В PHP >= 5.4 вы можете сделать обратный вызов еще короче:

$apples = array_filter($array, function($color) use ($&array) {
  return each($array)['key'] === 'apple';
}

Ответ 7

Здесь менее гибкая альтернатива, использующая unset():

$array = array(
    1 => 'one',
    2 => 'two',
    3 => 'three'
);
$disallowed = array(1,3);
foreach($disallowed as $key){
    unset($array[$key]);
}

Результат print_r($array):

Array
(
    [2] => two
)

Это неприменимо, если вы хотите сохранить отфильтрованные значения для последующего использования, но более аккуратные, если вы уверены, что этого не делаете.

Ответ 8

Начиная с PHP 5.6, вы можете использовать флаг ARRAY_FILTER_USE_KEY в array_filter:

$result = array_filter($my_array, function ($k) use ($allowed) {
    return in_array($k, $allowed);
}, ARRAY_FILTER_USE_KEY);


В противном случае вы можете использовать эту функцию (из TestDummy):

function filter_array_keys(array $array, $callback)
{
    $matchedKeys = array_filter(array_keys($array), $callback);

    return array_intersect_key($array, array_flip($matchedKeys));
}

$result = filter_array_keys($my_array, function ($k) use ($allowed) {
    return in_array($k, $allowed);
});


И вот расширенная версия моей, которая принимает обратный вызов или непосредственно ключи:

function filter_array_keys(array $array, $keys)
{
    if (is_callable($keys)) {
        $keys = array_filter(array_keys($array), $keys);
    }

    return array_intersect_key($array, array_flip($keys));
}

// using a callback, like array_filter:
$result = filter_array_keys($my_array, function ($k) use ($allowed) {
    return in_array($k, $allowed);
});

// or, if you already have the keys:
$result = filter_array_keys($my_array, $allowed));


И последнее, но не менее важное: вы также можете использовать простой foreach:

$result = [];
foreach ($my_array as $key => $value) {
    if (in_array($key, $allowed)) {
        $result[$key] = $value;
    }
}

Ответ 9

Возможно, излишний, если вам это нужно, только один раз, но вы можете использовать YaLinqo library * для фильтрации коллекций (и выполнять любые другие преобразования). Эта библиотека позволяет формировать SQL-подобные запросы на объектах с плавным синтаксисом. Функция where принимает возврат с двумя аргументами: значением и ключом. Например:

$filtered = from($array)
    ->where(function ($v, $k) use ($allowed) {
        return in_array($k, $allowed);
    })
    ->toArray();

(Функция where возвращает итератор, поэтому, если вам нужно только выполнить повторение с помощью foreach по полученной последовательности один раз, ->toArray() можно удалить.)

*, разработанный мной

Ответ 10

Функция фильтра массива из php:

array_filter ( $array, $callback_function, $flag )

$array - это входной массив

$callback_function - функция обратного вызова для использования. Если функция обратного вызова возвращает true, текущее значение из массива возвращается в массив результатов.

$flag - это необязательный параметр, он определит, какие аргументы отправляются функции обратного вызова. Если этот параметр пуст, то функция обратного вызова будет принимать значения массива в качестве аргумента. Если вы хотите отправить массив в качестве аргумента, используйте флаг $как ARRAY_FILTER_USE_KEY. Если вы хотите отправить обе клавиши и значения, вы должны использовать флаг $как ARRAY_FILTER_USE_BOTH.

Пример: Рассмотрим простой массив

$array = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);

Если вы хотите фильтровать массив на основе ключа массива, нам нужно использовать ARRAY_FILTER_USE_KEY как третий параметр функции массива array_filter.

$get_key_res = array_filter($array,"get_key",ARRAY_FILTER_USE_KEY );

Если вы хотите фильтровать массив на основе ключа массива и значения массива, нам нужно использовать ARRAY_FILTER_USE_BOTH как третий параметр функции массива array_filter.

$get_both = array_filter($array,"get_both",ARRAY_FILTER_USE_BOTH );

Примеры функций обратного вызова:

 function get_key($key)
 {
    if($key == 'a')
    {
        return true;
    } else {
        return false;
    }
}
function get_both($val,$key)
{
    if($key == 'a' && $val == 1)
    {
        return true;
    }   else {
        return false;
    }
}

Он выведет

Output of $get_key is :Array ( [a] => 1 ) 
Output of $get_both is :Array ( [a] => 1 ) 

Ответ 11

С помощью этой функции вы можете фильтровать многомерный массив

function filter_array_keys($array,$filter_keys=array()){

    $l=array(&$array);
    $c=1;
    //This first loop will loop until the count var is stable//
    for($r=0;$r<$c;$r++){
        //This loop will loop thru the child element list//
        $keys = array_keys($l[$r]);

        for($z=0;$z<count($l[$r]);$z++){
            $object = &$l[$r][$keys[$z]];

            if(is_array($object)){
                $i=0;
                $keys_on_array=array_keys($object);
                $object=array_filter($object,function($el) use(&$i,$keys_on_array,$filter_keys){
                    $key = $keys_on_array[$i];
                    $i++;

                    if(in_array($key,$filter_keys) || is_int($key))return false;                
                    return true;                        
                });
            }

            if(is_array($l[$r][$keys[$z]])){
                $l[] = &$l[$r][$keys[$z]];
                $c++;
            }//IF           
        }//FOR
    }//FOR  

    return $l[0];

}

Ответ 12

// Filter out array elements with keys shorter than 4 characters 
// By using Anonymous function with  Closure...     

function comparison($min)
{
   return function($item) use ($min) { 
      return strlen($item) >= $min;   
   }; 
}

$input = array(
  0      => "val 0",
  "one"  => "val one",
  "two"  => "val two",
  "three"=> "val three",
  "four" => "val four",  
  "five" => "val five",    
  "6"    => "val 6"    
);

$output = array_filter(array_keys($input), comparison(4));    

print_r($output);

Output from run

Ответ 13

$elements_array = ['first', 'second'];

функция для удаления некоторых элементов массива

function remove($arr, $data) {
    return array_filter($arr, function ($element) use ($data) {
        return $element != $data;
    });
}

позвоните и распечатайте

print_r(remove($elements_array, 'second'));

Array ( [0] => first ) результата Array ( [0] => first )