it-swarm.com.ru

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

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

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

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

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

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

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

$my_array = array("foo" => 1);
312
maček

В 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']
233
Richard Turner

С array_intersect_key и array_flip :

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

array(1) {
  ["foo"]=>
  int(1)
}
425
Vincent Savard

Мне нужно было сделать то же самое, но с более сложным 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
Christopher

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

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

Как получить текущий ключ массива при использовании 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
flu

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

$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
Nicolas Zimmer

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

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

3
Alastair

Начиная с 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
Gras Double

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

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

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

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

1
Athari

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

array_filter ( $array, $callback_function, $flag )

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

$ callback_function - Используемая функция обратного вызова. 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 ) 
0
prince jose

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

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
user1220713

// Отфильтровать элементы массива с ключами короче 4 символов // Используя анонимную функцию с Closure ... 

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 ($ выход);
enter image description here

0
ZOB