Cómo verificar si existen varias claves de matriz

8 minutos de lectura

avatar de usuario
Ryan

Tengo una variedad de arreglos que contendrán

story & message

o solo

story

¿Cómo verificaría si una matriz contiene tanto la historia como el mensaje? array_key_exists() solo busca esa clave única en la matriz.

¿Hay alguna forma de hacer esto?

  • Si la “historia” estará allí en cualquiera de los casos, parece que realmente solo necesita verificar el “mensaje”.

    – Mago

    1 de noviembre de 2012 a las 1:03

  • Usando array_intersect_key() compare una matriz de las claves que desea verificar con la matriz que está comprobando. Si la longitud de la salida es la misma que la matriz de claves para verificar, todas están presentes.

    –Michael Berkowski

    1 de noviembre de 2012 a las 1:04

  • Wyzard, tengo otras matrices que contienen mensaje, pero no historia, pero esas tienen otras claves que solo contendría una matriz con historia o historia y mensaje. Gracias

    – Ryan

    1 de noviembre de 2012 a las 1:07

  • ¿Estás confundiendo claves y valores aquí? ¿La matriz está formateada como ["story & message" => "value"] o es más como ["story & message"]

    – GordonM

    25 de enero de 2017 a las 9:34

avatar de usuario
Erfán

Aquí hay una solución que es escalable, incluso si desea verificar una gran cantidad de claves:

<?php

// The values in this arrays contains the names of the indexes (keys) 
// that should exist in the data array
$required = array('key1', 'key2', 'key3');

$data = array(
    'key1' => 10,
    'key2' => 20,
    'key3' => 30,
    'key4' => 40,
);

if (count(array_intersect_key(array_flip($required), $data)) === count($required)) {
    // All required keys exist!
}

  • Me gustaría saber la razón por la que esto fue rechazado. Afaik, esto es más rápido porque array_intersect_key está implementado en C y no necesitará un bucle.

    – Erfán

    16 de agosto de 2013 a las 1:09

  • Bastante inteligente en realidad, bien hecho, aunque un poco difícil de leer.

    – Jon z

    26/10/2013 a las 16:06


  • Gracias 🙂 Es extraño que PHP no tenga una función incorporada para hacer esto, es bastante común. Hay toneladas de clases de validación de entrada de usuario que hacen esto, pero para la mayoría de los casos de uso es una exageración

    – Erfán

    30 de octubre de 2013 a las 8:35

  • De hecho, es una solución inteligente, pero es realmente más lenta (alrededor de un 50 % más lenta en mi caja) que una sencilla: “` $ok = true; foreach( $requerido como $campo ) { if( !array_key_exists( $campo, $datos ) ) $ok = false; }

    – Oz

    24 de diciembre de 2013 a las 17:29


  • @Ozh aparte de que array_key_exists es más lento que isset

    – iautomatización

    1 de marzo de 2016 a las 22:49

avatar de usuario
Alex

Si solo tiene 2 claves para verificar (como en la pregunta original), probablemente sea bastante fácil simplemente llamar array_key_exists() dos veces para verificar si las claves existen.

if (array_key_exists("story", $arr) && array_key_exists("message", $arr)) {
    // Both keys exist.
}

Sin embargo, esto obviamente no se adapta bien a muchas teclas. En esa situación, una función personalizada ayudaría.

function array_keys_exists(array $keys, array $arr) {
   return !array_diff_key(array_flip($keys), $arr);
}

  • Si las personas piensan que las otras soluciones son mejores para verificar si una matriz tiene dos miembros presentes, no les debe gustar el código legible claro o el rendimiento 🙂

    – Alex

    16 de marzo de 2016 a las 8:30

  • Esta es probablemente la solución más simple si las claves requeridas son relativamente pocas. Si se volverá ilegible si son algo así como 20 o 30.

    – apokryfos

    9 mayo 2016 a las 12:34

  • @apokryfos De acuerdo, pero responde la pregunta del OP.

    – Alex

    9 mayo 2016 a las 12:51

  • @alex el único problema es que si $keys contiene un elemento que no está en $arr y otro que está en ella, !array_diff_key devuelve vacío => false (ejemplo 3v4l)…

    – CPH Python

    17 de agosto de 2018 a las 10:10

  • Creo que esto se puede hacer más legible usando !array_diff($keys, array_keys($array)); porque hay un poco menos de carga cognitiva involucrada en la elaboración de esos array_flips.

    – Moopet

    29 de marzo de 2019 a las 12:05

avatar de usuario
marca zorro

Asombrosamente array_keys_exist no existe?! Mientras tanto, deja algo de espacio para encontrar una expresión de una sola línea para esta tarea común. Estoy pensando en un script de shell u otro programa pequeño.

Nota: cada una de las siguientes soluciones utiliza conciso […] sintaxis de declaración de matriz disponible en php 5.4+

array_diff + array_keys

if (0 === count(array_diff(['story', 'message', '…'], array_keys($source)))) {
  // all keys found
} else {
  // not all
}

(punta de sombrero para Kim Stacks)

Este enfoque es el más breve que he encontrado. array_diff() devuelve una matriz de elementos presentes en el argumento 1 no presente en el argumento 2. Por lo tanto, una matriz vacía indica que se encontraron todas las claves. En php 5.5 podrías simplificar 0 === count(…) ser simplemente empty(…).

array_reduce + desarmar

if (0 === count(array_reduce(array_keys($source), 
    function($in, $key){ unset($in[array_search($key, $in)]); return $in; }, 
    ['story', 'message', '…'])))
{
  // all keys found
} else {
  // not all
}

Más difícil de leer, fácil de cambiar. array_reduce() utiliza una devolución de llamada para iterar sobre una matriz para llegar a un valor. Al alimentar las claves estamos interesados ​​en el $initial valor de $in y luego eliminando las claves encontradas en la fuente, podemos esperar terminar con 0 elementos si se encontraron todas las claves.

La construcción es fácil de modificar ya que las teclas que nos interesan encajan muy bien en la línea inferior.

matriz_filtro & en_matriz

if (2 === count(array_filter(array_keys($source), function($key) { 
        return in_array($key, ['story', 'message']); }
    )))
{
  // all keys found
} else {
  // not all
}

Más fácil de escribir que el array_reduce solución pero un poco más engañosa de editar. array_filter también es una devolución de llamada iterativa que le permite crear una matriz filtrada devolviendo verdadero (copie el elemento a la nueva matriz) o falso (no copie) en la devolución de llamada. El problema es que debes cambiar 2 al número de artículos que espera.

Esto se puede hacer más duradero, pero está al borde de una legibilidad absurda:

$find = ['story', 'message'];
if (count($find) === count(array_filter(array_keys($source), function($key) use ($find) { return in_array($key, $find); })))
{
  // all keys found
} else {
  // not all
}

  • la diferencia será insignificante para conjuntos pequeños. si está escribiendo una biblioteca/marco que maneja grandes conjuntos de datos, probablemente debería probar el rendimiento de cada unidad para encontrar cuellos de botella en lugar de optimizar prematuramente.

    – Marcos Fox

    25 de noviembre de 2014 a las 19:17

avatar de usuario
petr cibulka

Me parece que el método más fácil, con mucho, sería este:

$required = array('a','b','c','d');

$values = array(
    'a' => '1',
    'b' => '2'
);

$missing = array_diff_key(array_flip($required), $values);

Huellas dactilares:

Array(
    [c] => 2
    [d] => 3
)

Esto también permite verificar qué teclas faltan exactamente. Esto podría ser útil para el manejo de errores.

avatar de usuario
Vasili

Una posible solución más:

if (!array_diff(['story', 'message'], array_keys($array))) {
    // OK: all the keys are in $array
} else {
   // FAIL: some keys are not
}

Las soluciones anteriores son inteligentes, pero muy lentas. Un bucle foreach simple con isset es más del doble de rápido que el array_intersect_key solución.

function array_keys_exist($keys, $array){
    foreach($keys as $key){
        if(!array_key_exists($key, $array))return false;
    }
    return true;
}

(344ms frente a 768ms para 1000000 iteraciones)

avatar de usuario
Sven

Si tienes algo como esto:

$stuff = array();
$stuff[0] = array('story' => 'A story', 'message' => 'in a bottle');
$stuff[1] = array('story' => 'Foo');

Podrías simplemente count():

foreach ($stuff as $value) {
  if (count($value) == 2) {
    // story and message
  } else {
    // only story
  }
}

Esto solo funciona si está seguro de que SOLO tiene estas claves de matriz, y nada más.

El uso de array_key_exists() solo admite la verificación de una clave a la vez, por lo que deberá verificar ambas por separado:

foreach ($stuff as $value) {
  if (array_key_exists('story', $value) && array_key_exists('message', $value) {
    // story and message
  } else {
    // either one or both keys missing
  }
}

array_key_exists() devuelve verdadero si la clave está presente en la matriz, pero es una función real y mucho para escribir. La construcción del lenguaje isset() casi hará lo mismo, excepto si el valor probado es NULL:

foreach ($stuff as $value) {
  if (isset($value['story']) && isset($value['message']) {
    // story and message
  } else {
    // either one or both keys missing
  }
}

Además, isset permite verificar múltiples variables a la vez:

foreach ($stuff as $value) {
  if (isset($value['story'], $value['message']) {
    // story and message
  } else {
    // either one or both keys missing
  }
}

Ahora, para optimizar la prueba para las cosas que están configuradas, será mejor que uses este “si”:

foreach ($stuff as $value) {
  if (isset($value['story']) {
    if (isset($value['message']) {
      // story and message
    } else {
      // only story
    }
  } else {
    // No story - but message not checked
  }
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad