Cómo buscar por clave=>valor en una matriz multidimensional en PHP
¿Existe alguna forma rápida de obtener todos los subarreglos donde se encontró un par clave-valor en una matriz multidimensional? No puedo decir qué tan profunda será la matriz.
Matriz de ejemplo simple:
$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1")
);
Cuando busco clave=nombre y valor="cat 1", la función debería devolver:
array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>3,name=>"cat 1")
);
Supongo que la función tiene que ser recursiva para llegar al nivel más profundo.
Código:
function search($array, $key, $value)
{
$results = array();
if (is_array($array)) {
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
$results = array_merge($results, search($subarray, $key, $value));
}
}
return $results;
}
$arr = array(0 => array(id=>1,name=>"cat 1"),
1 => array(id=>2,name=>"cat 2"),
2 => array(id=>3,name=>"cat 1"));
print_r(search($arr, 'name', 'cat 1'));
Producción:
Array
(
[0] => Array
(
[id] => 1
[name] => cat 1
)
[1] => Array
(
[id] => 3
[name] => cat 1
)
)
Si la eficiencia es importante, puede escribirlo de modo que todas las llamadas recursivas almacenen sus resultados en la misma $results
matriz temporal en lugar de fusionar matrices, así:
function search($array, $key, $value)
{
$results = array();
search_r($array, $key, $value, $results);
return $results;
}
function search_r($array, $key, $value, &$results)
{
if (!is_array($array)) {
return;
}
if (isset($array[$key]) && $array[$key] == $value) {
$results[] = $array;
}
foreach ($array as $subarray) {
search_r($subarray, $key, $value, $results);
}
}
La clave es que search_r
toma su cuarto parámetro por referencia y no por valor; el signo comercial &
es crucial.
Para su información: si tiene una versión anterior de PHP, debe especificar la parte de paso por referencia en la llamada a search_r
en lugar de en su declaración. Es decir, la última línea se convierte en search_r($subarray, $key, $value, &$results)
.
¿Qué tal la versión SPL ? Te ahorrará algo de escribir:
// I changed your input example to make it harder and
// to show it works at lower depths:
$arr = array(0 => array('id'=>1,'name'=>"cat 1"),
1 => array(array('id'=>3,'name'=>"cat 1")),
2 => array('id'=>2,'name'=>"cat 2")
);
//here's the code:
$arrIt = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
foreach ($arrIt as $sub) {
$subArray = $arrIt->getSubIterator();
if ($subArray['name'] === 'cat 1') {
$outputArray[] = iterator_to_array($subArray);
}
}
Lo bueno es que básicamente el mismo código se repetirá a través de un directorio, utilizando un RecursiveDirectoryIterator en lugar de un RecursiveArrayIterator. SPL es el roxor.
Lo único malo de SPL es que está mal documentado en la web. Pero varios libros de PHP entran en detalles útiles, particularmente Pro PHP; Y probablemente también puedas buscar en Google más información.
<?php
$arr = array(0 => array("id"=>1,"name"=>"cat 1"),
1 => array("id"=>2,"name"=>"cat 2"),
2 => array("id"=>3,"name"=>"cat 1")
);
$arr = array_filter($arr, function($ar) {
return ($ar['name'] == 'cat 1');
//return ($ar['name'] == 'cat 1' AND $ar['id'] == '3');// you can add multiple conditions
});
echo "<pre>";
print_r($arr);
?>
Ref: http://php.net/manual/en/function.array-filter.php
Volví para publicar esta actualización para cualquiera que necesite un consejo de optimización sobre estas respuestas, en particular la excelente respuesta de John Kugelman arriba.
Su función publicada funciona bien, pero tuve que optimizar este escenario para manejar un conjunto de resultados de 12 000 filas. La función tardaba 8 segundos eternos en revisar todos los registros, muuuucho tiempo.
Simplemente necesitaba la función para DETENER la búsqueda y regresar cuando se encontrara una coincidencia. Es decir, si buscamos un customer_id, sabemos que solo tenemos uno en el conjunto de resultados y una vez que encontramos el customer_id en la matriz multidimensional, queremos regresar.
Aquí está la versión de velocidad optimizada (y muy simplificada) de esta función, para cualquiera que la necesite. A diferencia de otras versiones, solo puede manejar una profundidad de matriz, no es recurrente y elimina la combinación de múltiples resultados.
// search array for specific key = value
public function searchSubArray(Array $array, $key, $value) {
foreach ($array as $subarray){
if (isset($subarray[$key]) && $subarray[$key] == $value)
return $subarray;
}
}
Esto redujo la tarea de hacer coincidir los 12.000 registros a 1,5 segundos. Sigue siendo muy costoso pero mucho más razonable.