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

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

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

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

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

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

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

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

13 ответов


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

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


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

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

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
)

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

он передает массив, который вы фильтруете, как ссылку на обратный вызов. As array_filter обычно не выполняет итерацию по массиву, увеличивая его общедоступность указатель вы должны продвигать его самостоятельно.

важно то, что вам нужно убедиться, что Ваш массив сброшен, иначе вы можете начать прямо посреди него.

на PHP >= 5.4 вы можете сделать обратный вызов еще короче:

$apples = array_filter($array, function($color) use ($&array) {
  return each($array)['key'] === 'apple';
}

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

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


начиная с 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);
});


А вот дополненная версия mine, которая принимает обратный вызов или непосредственно ключи:

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

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

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

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

* я


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

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

}

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

array_filter ( $array, $callback_function, $flag )

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

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

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

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

$output = array_filter(array_keys ($input), сравнение (4));

print_r ($output);
enter image description here


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