PHP: как использовать array filter() для фильтрации ключей массива?
функция обратного вызова в array_filter() передает только значения массива, а не ключи.
если у меня есть:
$my_array = array("foo" => 1, "hello" => "world");
$allowed = array("foo", "bar");
каков наилучший способ удалить все ключи в $my_array не в $allowed массив?
желаемый результат:
$my_array = array("foo" => 1);
13 ответов:
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']
С
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]); }результат
print_r($array)время:Array ( [2] => two )Это не применимо, если вы хотите сохранить отфильтрованы значения для последующего использования, но аккуратнее, если вы уверены, что это не так.
начиная с 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; } }
возможно, перебор, если вам это нужно только один раз, но вы можете использовать YaLinqo библиотека* для фильтрации коллекций (и выполнения любых других преобразований). Эта библиотека позволяет формировать SQL-подобные запросы на объекты с плавным синтаксисом. Его
whereфункция принимает обратный вызов с двумя аргументами: значение и ключ. Например:$filtered = from($array) ->where(function ($v, $k) use ($allowed) { return in_array($k, $allowed); }) ->toArray();(The
whereфункция возвращает итератор, так что если вам нужно только перебрать сforeachпо результирующей последовательности один раз,->toArray()можно удалить.)* я
С помощью этой функции можно фильтровать многомерный массив
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 - функция обратного вызова для использования, если функция обратного вызова возвращает правда, текущее значение из массива возвращается в результирующий массив.
$флаг - это необязательный параметр, он определит, какие аргументы отправляются в функцию обратного вызова. Если этот параметр пуст, то функция будет принимать значения массива аргумент. Если вы хотите отправить ключ массива в качестве аргумента, то используйте $ 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 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 символов // С помощью анонимной функции с закрытием...
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));
$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 )

Comments