Web

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

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

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

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

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

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

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

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

 

 Ответ 1

Можно использовать функции array_intersect_key и array_flip:

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

array(1) {

  ["foo"]=>

  int(1)

}

 

Ответ 2

В 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

);

 Поскольку в PHP 7.4 появились стрелочные функции, мы можем сделать этот код более лаконичным:

$my_array = ['foo' => 1, 'hello' => 'world'];

$allowed  = ['foo', 'bar'];

$filtered = array_filter(

    $my_array,

    fn ($key) => 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,

    // N.b. it's ($val, $key) not ($key, $val):

    fn ($val, $key) => isset($allowed[$key]) && (

        $allowed[$key] === true || $allowed[$key] === $val

    ),

    ARRAY_FILTER_USE_BOTH

); // ['foo' => 1, 'bar' => 'baz']

 

Ответ 3

Мне нужно было сделать то же самое, но с более сложными ключами array_filter. Вот как я это сделал, используя похожий метод.

// Отфильтровываем элементы массива с ключами короче 4 символов

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

 

$array = ['apple' => 'red', 'pear' => 'green'];

reset($array); // Здесь это не важно, но убедитесь, что ваш массив сброшен.

$apples = array_filter($array, function($color) use ($&array) {

  $key = key($array);

  next($array); // продвигаем указатель массива

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

}

 Этот код передает массив, который вы фильтруете, как ссылку на обратный вызов. Поскольку array_filter обычно не выполняет итерации по массиву путем увеличения его общедоступного внутреннего указателя, вы должны продвигать его самостоятельно. Здесь важно то, что вам нужно убедиться, что ваш массив сброшен, иначе вы можете начать перебор прямо с его середины. В PHP> = 5.4 вы можете сделать обратный вызов еще короче:

$apples = array_filter($array, function($color) use ($&array) {

  return each($array)['key'] === 'apple';

}

 

 

Схожие статьи

Что такое локальное хранилище и как его используют в программировании
Web

Что такое локальное хранилище и как его используют в программировании

Web

Когда я использую Plesk, отображается фатальная ошибка PHP

Web

Как преобразовать серию «родитель-потомок» в иерархическое дерево

Web

Когда использовать константу PHP «PHP_EOL»