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


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

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

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

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

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

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

$my_array = array("foo" => 1);
 293
Author: Jeff Puckett, 2010-11-23

13 answers

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']
 206
Author: Richard Turner, 2017-05-23 12:26:32

С array_intersect_key и array_flip:

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

array(1) {
  ["foo"]=>
  int(1)
}
 411
Author: Vincent Savard, 2016-03-21 14:51:43

Мне нужно было сделать то же самое, но с более сложным 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
)
 39
Author: Christopher, 2013-01-25 20:02:18

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

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

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

 8
Author: COil, 2013-01-25 10:38:49

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

$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
)
 4
Author: Nicolas Zimmer, 2014-03-02 20:05:07

Как получить текущий ключ массива при использовании 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
Author: flu, 2015-05-13 09:42:12

Вот менее гибкая альтернатива, использующая неустановленный():

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

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

 3
Author: Alastair, 2012-10-31 03:50:40

Начиная с 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
Author: Gras Double, 2015-12-17 12:49:44

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

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

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

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

 1
Author: Athari, 2015-06-04 00:19:55

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

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

}
 0
Author: user1220713, 2016-03-15 09:41:44

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

array_filter ( $array, $callback_function, $flag )

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

$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 ) 
 0
Author: prince jose, 2017-01-11 03:14:07

//Отфильтровать элементы массива с ключами короче 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"    
);

$вывод = array_filter(array_keys($ввод), сравнение(4));

Print_r($вывод);
enter image description here

 0
Author: ZOB, 2017-10-24 12:53:47
$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 )

 0
Author: Abdallah Awwad Alkhwaldah, 2018-08-24 08:02:24