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

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

Если бы у меня был:

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

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

Желаемый результат:

 $my_array = array("foo" => 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 this:

 $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) { // Nb $val, $key not $key, $val return isset($allowed[$key]) && ( $allowed[$key] === true || $allowed[$key] === $val ); }, ARRAY_FILTER_USE_BOTH ); // ['foo' => 1, 'bar' => 'baz'] 

С помощью array_intersect_key и array_flip :

 var_dump(array_intersect_key($my_array, array_flip($allowed))); array(1) { ["foo"]=> int(1) } 

Мне нужно было сделать то же самое, но с более сложным 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 ) 

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

 $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) } 

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

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

 $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 ) 

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

Независимо от того, как мне нравится решение Винсента по проблеме Мачека, на самом деле он не использует 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 традиционно не перебирает массив, увеличивая его внутренний внутренний указатель, вы должны его самостоятельно продвигать.

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

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

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

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

 $array = array( 1 => 'one', 2 => 'two', 3 => 'three' ); $disallowed = array(1,3); foreach($disallowed as $key){ unset($array[$key]); } с $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 ) 

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

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

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

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

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

Начиная с PHP 5.6, вы можете использовать флаг array_filter в 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; } } 

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

 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]; } 

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

 array_filter ( $array, $callback_function, $flag ) 

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

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

$ flag – это необязательный параметр , он будет определять, какие аргументы отправляются на функцию обратного вызова. Если этот параметр пуст, то функция обратного вызова будет принимать значения массива в качестве аргумента. Если вы хотите отправить массив в качестве аргумента, используйте флаг $ как ARRAY_FILTER_USE_KEY . Если вы хотите отправить оба ключа и значения, вы должны использовать $ flag как 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 ) 

// Отфильтровать элементы массива с ключами длиной не более 4 символов // Используя функцию Anonymous с закрытием …

 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), сравнение (4));

print_r ($ выход);
введите описание изображения здесь