¿Cómo filtrar una matriz asociativa comparando claves con valores en una matriz indexada?

Resuelto maček asked hace 54 años • 12 respuestas

La función de devolución de llamada array_filter()solo pasa los valores de la matriz, no las claves.

Si tengo:

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

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

¿ Cuál es la mejor manera de eliminar todas las claves $my_arrayque no están en la $allowedmatriz?

Salida deseada:

$my_array = array("foo" => 1);
maček avatar Jan 01 '70 08:01 maček
Aceptado

Con array_intersect_keyy array_flip:

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

array(1) {
  ["foo"]=>
  int(1)
}
Vincent Savard avatar Nov 23 '2010 19:11 Vincent Savard

PHP 5.6 introdujo un tercer parámetro en array_filter(), flagque puede configurar ARRAY_FILTER_USE_KEYpara filtrar por clave en lugar de valor:

$my_array = ['foo' => 1, 'hello' => 'world'];
$allowed  = ['foo', 'bar'];
$filtered = array_filter(
    $my_array,
    function ($key) use ($allowed) {
        // N.b. in_array() is notorious for being slow 
        return in_array($key, $allowed);
    },
    ARRAY_FILTER_USE_KEY
);

Dado que PHP 7.4 introdujo funciones de flecha, podemos hacer esto más conciso:

$my_array = ['foo' => 1, 'hello' => 'world'];
$allowed  = ['foo', 'bar'];
$filtered = array_filter(
    $my_array,
    fn ($key) => in_array($key, $allowed),
    ARRAY_FILTER_USE_KEY
);

Claramente esto no es tan elegante como array_intersect_key($my_array, array_flip($allowed)), pero ofrece la flexibilidad adicional de realizar una prueba arbitraria contra la clave; por ejemplo, $allowedpodría contener patrones de expresiones regulares en lugar de cadenas simples.

También puede utilizar ARRAY_FILTER_USE_BOTHpara pasar tanto el valor como la clave a su función de filtro. Aquí hay un ejemplo artificial basado en el primero, pero tenga en cuenta que no recomendaría codificar reglas de filtrado de $allowedesta manera:

$my_array = ['foo' => 1, 'bar' => 'baz', 'hello' => 'wld'];
$allowed  = ['foo' => true, 'bar' => true, 'hello' => 'world'];
$filtered = array_filter(
    $my_array,
    fn ($val, $key) => isset($allowed[$key]) && (
        $allowed[$key] === true || $allowed[$key] === $val
    ),
    ARRAY_FILTER_USE_BOTH
); // ['foo' => 1, 'bar' => 'baz']
Richard Turner avatar Oct 23 '2014 08:10 Richard Turner

Aquí hay una solución más flexible usando un cierre:

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

Salidas:

array(1) {
  'foo' =>
  int(1)
}

Entonces, en la función, puedes hacer otras pruebas específicas.

COil avatar Jan 25 '2013 10:01 COil

Aquí hay una alternativa menos flexible usando unset() :

$array = array(
    1 => 'one',
    2 => 'two',
    3 => 'three'
);
$disallowed = array(1,3);
foreach($disallowed as $key){
    unset($array[$key]);
}

El resultado de print_r($array)ser:

Array
(
    [2] => two
)

Esto no se aplica si desea conservar los valores filtrados para su uso posterior, pero de manera más ordenada, si está seguro de que no es así.

Alastair avatar Oct 31 '2012 03:10 Alastair

Si está buscando un método para filtrar una matriz por una cadena que aparece en las claves, puede usar:

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

El resultado de print_r($mResult)es

Array ( [foo] => bar [foo2] => bar2 [fooToo] => bar3 )

Una adaptación de esta respuesta que admite expresiones regulares.

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"));

Producción

Array
(
    [foo] => yes
    [foo2] => yes
    [FooToo] => yes
)
Nicolas Zimmer avatar Feb 28 '2014 16:02 Nicolas Zimmer