Функция обратного вызова в array_filter()
передает только значения массива, а не ключи.
Если у меня есть:
$my_array = array("foo" => 1, "hello" => "world");
$allowed = array("foo", "bar");
Какой лучший способ удалить все ключи в $my_array
, которые не входят в массив $allowed
?
Требуемый вывод:
$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
следующим образом:
$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
С 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)
}
Таким образом, в функции вы можете выполнять другие специальные тесты.
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';
}
Если вы ищете метод фильтрации массива по строке, входящей в ключи, вы можете использовать:
$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
)
stristr
в «работе» функции делает некоторые предположения для конечного пользователя. Возможно, было бы лучше позволить пользователю передавать регулярное выражение; это дало бы им больше гибкости в отношении определенных вещей, таких как привязки, границы слов, чувствительность к регистру и т. д.
Начиная с 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;
}
}
Здесь менее гибкая альтернатива, использующая 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
)
Это неприменимо, если вы хотите сохранить отфильтрованные значения для последующего использования, но более аккуратные, если вы уверены, что этого не делаете.
unset()
. Предупреждения не выдаются, если ключ не существует.
Возможно, излишний, если вам это нужно, только один раз, но вы можете использовать YaLinqo library * для фильтрации коллекций (и выполнять любые другие преобразования). Эта библиотека позволяет формировать SQL-подобные запросы на объектах с плавным синтаксисом. Функция where
принимает возврат с двумя аргументами: значением и ключом. Например:
$filtered = from($array)
->where(function ($v, $k) use ($allowed) {
return in_array($k, $allowed);
})
->toArray();
(Функция where
возвращает итератор, поэтому, если вам нужно только выполнить повторение с помощью foreach
по полученной последовательности один раз, ->toArray()
можно удалить.)
*, разработанный мной
//Отфильтровать элементы массива с ключами короче 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 ($ выход);
Функция фильтра массива из 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 )
С помощью этой функции вы можете фильтровать многомерный массив
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];
}
$b = ['foo' => $a['foo'], 'bar' => $a['bar']]
Это приведет к$b['bar']
будетnull
.