PHP: Как использовать array_filter () для фильтрации ключей массива? - PullRequest
325 голосов
/ 23 ноября 2010

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

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

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

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

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

Желаемый вывод:

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

Ответы [ 13 ]

438 голосов
/ 23 ноября 2010

С array_intersect_key и array_flip:

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

array(1) {
  ["foo"]=>
  int(1)
}
261 голосов
/ 23 октября 2014

В 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 может содержать шаблоны регулярных выражений вместо простогоstrings.

Вы также можете использовать 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']
39 голосов
/ 27 августа 2012

Мне нужно было сделать то же самое, но с более сложным 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
)
8 голосов
/ 25 января 2013

Вот более гибкое решение с использованием замыкания:

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

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

4 голосов
/ 23 января 2015

Как получить текущий ключ массива при использовании 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';
}
4 голосов
/ 28 февраля 2014

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

$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
)
3 голосов
/ 29 августа 2015

Начиная с 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;
    }
}
3 голосов
/ 31 октября 2012

Вот менее гибкая альтернатива с использованием 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
)

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

1 голос
/ 11 января 2017

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

array_filter ( $array, $callback_function, $flag )

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

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...