Comprobando si ALGUNO de los elementos de una matriz está en otra matriz

9 minutos de lectura

Avatar de usuario de Philip Morton
felipe morton

Tengo dos matrices en PHP de la siguiente manera:

Gente:

Array
(
    [0] => 3
    [1] => 20
)

Criminales buscados:

Array
(
    [0] => 2
    [1] => 4
    [2] => 8
    [3] => 11
    [4] => 12
    [5] => 13
    [6] => 14
    [7] => 15
    [8] => 16
    [9] => 17
    [10] => 18
    [11] => 19
    [12] => 20
)

¿Cómo verifico si alguna de El Gente los elementos están en el Criminales buscados ¿formación?

En este ejemplo, debería devolver true porque 20 es en Criminales buscados.

Avatar de usuario de Greg
greg

Puedes usar array_intersect().

$peopleContainsCriminal = !empty(array_intersect($people, $criminals));

  • No se puede usar empty() con otra cosa que no sea una variable.

    – parques de subvenciones

    25 de septiembre de 2009 a las 19:21

  • Desde la página a la que se vinculó: “Antes de PHP 5.5, vacío () solo admite variables; cualquier otra cosa dará como resultado un error de análisis. En otras palabras, lo siguiente no funcionará: vacío (trim ($ nombre)). En su lugar, use trim ($ nombre) == falso”.

    – parques de subvenciones

    19/09/2013 a las 22:31

  • Como se mencionó en los comentarios, encontré que !empty no funciona como se esperaba. En cambio, usé count(): !count(array_intersect($people, $criminals));

    – Mattios550

    30 de noviembre de 2016 a las 21:12

  • ¿Por qué está marcado como la respuesta con 65 votos cuando arroja un error fatal: no se puede usar el valor de retorno de la función en el contexto de escritura?

    – Dave Heq

    27 de enero de 2017 a las 18:02

  • Usando !empty() es innecesario Simplemente convierta la matriz devuelta en un tipo de datos bool. $result = (bool) array_intersect(...); No hay razón para llamar empty() o count(). Una matriz vacía se convierte en false una matriz no vacía se convierte en true.

    – mickmackusa

    21 de febrero de 2022 a las 2:16

avatar de usuario de papsy
papi

Hay poco de malo en usar array_intersect() y count() (en lugar de vacío).

Por ejemplo:

$bFound = (count(array_intersect($criminals, $people))) ? true : false;

  • No tiene nada de malo, pero count() no se considera de alto rendimiento (si le importa la microoptimización, eso es)

    – Jake A. Smith

    14 mayo 2014 a las 21:25

  • El operador ternario es redundante en este código, puede analizarlo directamente como un bool llamando (bool) delante de count

    – Ben Gooding

    6 ago 2020 a las 16:00

  • solo puedo hacerlo $bFound = count(array_intersect($criminals, $people)) > 0;

    – Lionel Chan

    23 de diciembre de 2020 a las 1:51

  • Más simple aún: $bFound = (bool) array_intersect($criminals, $people); porque las matrices vacías son falsas.

    – mickmackusa

    20 de diciembre de 2022 a las 22:04


si ‘vacío’ no es la mejor opción, ¿qué pasa con esto:

if (array_intersect($people, $criminals)) {...} //when found

o

if (!array_intersect($people, $criminals)) {...} //when not found

Avatar de usuario de Paul Dragoonis
Pablo Dragonis

Ese código no es válido ya que solo puede pasar variables a construcciones de lenguaje. empty() es una construcción del lenguaje.

Tienes que hacer esto en dos líneas:

$result = array_intersect($people, $criminals);
$result = !empty($result);

Avatar de usuario de Frank Forte
franco fuerte

Prueba de rendimiento para in_array vs array_intersect:

$a1 = array(2,4,8,11,12,13,14,15,16,17,18,19,20);

$a2 = array(3,20);

$intersect_times = array();
$in_array_times = array();
for($j = 0; $j < 10; $j++)
{
    /***** TEST ONE array_intersect *******/
    $t = microtime(true);
    for($i = 0; $i < 100000; $i++)
    {
        $x = array_intersect($a1,$a2);
        $x = empty($x);
    }
    $intersect_times[] = microtime(true) - $t;


    /***** TEST TWO in_array *******/
    $t2 = microtime(true);
    for($i = 0; $i < 100000; $i++)
    {
        $x = false;
        foreach($a2 as $v){
            if(in_array($v,$a1))
            {
                $x = true;
                break;
            }
        }
    }
    $in_array_times[] = microtime(true) - $t2;
}

echo '<hr><br>'.implode('<br>',$intersect_times).'<br>array_intersect avg: '.(array_sum($intersect_times) / count($intersect_times));
echo '<hr><br>'.implode('<br>',$in_array_times).'<br>in_array avg: '.(array_sum($in_array_times) / count($in_array_times));
exit;

Aquí están los resultados:

0.26520013809204
0.15600109100342
0.15599989891052
0.15599989891052
0.1560001373291
0.1560001373291
0.15599989891052
0.15599989891052
0.15599989891052
0.1560001373291
array_intersect avg: 0.16692011356354

0.015599966049194
0.031199932098389
0.031200170516968
0.031199932098389
0.031200885772705
0.031199932098389
0.031200170516968
0.031201124191284
0.031199932098389
0.031199932098389
in_array avg: 0.029640197753906

in_array es al menos 5 veces más rápido. Tenga en cuenta que “rompemos” tan pronto como se encuentra un resultado.

  • Gracias por el punto de referencia. Entonces, si sabe que está manejando arreglos pequeños, es mejor quedarse con array_intersect().

    – Tokeeen.com

    2 de noviembre de 2017 a las 15:01

  • isset es aún más rápido. Y podría usar bool val para habilitar o deshabilitar. Además, los valores de búsqueda como clave se aseguran de no tener duplicados. ‘array_intersect promedio: 0.52077736854553; promedio en matriz: 0.015597295761108; promedio de isset: 0.0077081203460693´

    – algodón

    18 de junio de 2019 a las 12:03


  • Es aún más rápido si usa in_array con el conjunto booleano estricto. Pruebe los promedios 3 veces más rápido que sin el conjunto booleano estricto.

    – omarjebari

    24 de abril de 2021 a las 10:39

  • Es injusto hacer la comparación de referencia para array_intersect() también llamar empty(). empty() no es necesario en absoluto. !array_intersect() es suficiente para hacer el trabajo porque no hay necesidad de comprobar si $x se declara.

    – mickmackusa

    10 de enero a las 21:27

También podría usar in_array de la siguiente manera:

<?php
$found = null;
$people = array(3,20,2);
$criminals = array( 2, 4, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
foreach($people as $num) {
    if (in_array($num,$criminals)) {
        $found[$num] = true;
    } 
}
var_dump($found);
// array(2) { [20]=> bool(true)   [2]=> bool(true) }

Si bien array_intersect es ciertamente más conveniente de usar, resulta que no es realmente superior en términos de rendimiento. Creé este script también:

<?php
$found = null;
$people = array(3,20,2);
$criminals = array( 2, 4, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
$fastfind = array_intersect($people,$criminals);
var_dump($fastfind);
// array(2) { [1]=> int(20)   [2]=> int(2) }

Luego, ejecuté ambos fragmentos respectivamente en: http://3v4l.org/WGhO7/perf#tabs y http://3v4l.org/g1Hnu/perf#tabs y verificó el desempeño de cada uno. Lo interesante es que el tiempo total de la CPU, es decir, el tiempo del usuario + el tiempo del sistema es el mismo para PHP5.6 y la memoria también es la misma. El tiempo total de CPU bajo PHP5.4 es menor para in_array que para array_intersect, aunque marginalmente.

  • Gracias por el punto de referencia. Entonces, si sabe que está manejando arreglos pequeños, es mejor quedarse con array_intersect().

    – Tokeeen.com

    2 de noviembre de 2017 a las 15:01

  • isset es aún más rápido. Y podría usar bool val para habilitar o deshabilitar. Además, los valores de búsqueda como clave se aseguran de no tener duplicados. ‘array_intersect promedio: 0.52077736854553; promedio en matriz: 0.015597295761108; promedio de isset: 0.0077081203460693´

    – algodón

    18 de junio de 2019 a las 12:03


  • Es aún más rápido si usa in_array con el conjunto booleano estricto. Pruebe los promedios 3 veces más rápido que sin el conjunto booleano estricto.

    – omarjebari

    24 de abril de 2021 a las 10:39

  • Es injusto hacer la comparación de referencia para array_intersect() también llamar empty(). empty() no es necesario en absoluto. !array_intersect() es suficiente para hacer el trabajo porque no hay necesidad de comprobar si $x se declara.

    – mickmackusa

    10 de enero a las 21:27

avatar de usuario de agm1984
agm1984

Aquí hay una forma en que lo estoy haciendo después de investigarlo por un tiempo. Quería crear un punto final de API de Laravel que verifique si un campo está “en uso”, por lo que la información importante es: 1) ¿Qué tabla de base de datos? 2) ¿Qué columna DB? y 3) ¿hay algún valor en esa columna que coincida con los términos de búsqueda?

Sabiendo esto, podemos construir nuestra matriz asociativa:

$SEARCHABLE_TABLE_COLUMNS = [
    'users' => [ 'email' ],
];

Luego, podemos establecer nuestros valores que comprobaremos:

$table="users";
$column = 'email';
$value="alice@bob.com";

Entonces, podemos usar array_key_exists() y in_array() entre sí para ejecutar un combo de uno, dos pasos y luego actuar sobre el truthy condición:

// step 1: check if 'users' exists as a key in `$SEARCHABLE_TABLE_COLUMNS`
if (array_key_exists($table, $SEARCHABLE_TABLE_COLUMNS)) {

    // step 2: check if 'email' is in the array: $SEARCHABLE_TABLE_COLUMNS[$table]
    if (in_array($column, $SEARCHABLE_TABLE_COLUMNS[$table])) {

        // if table and column are allowed, return Boolean if value already exists
        // this will either return the first matching record or null
        $exists = DB::table($table)->where($column, '=', $value)->first();

        if ($exists) return response()->json([ 'in_use' => true ], 200);
        return response()->json([ 'in_use' => false ], 200);
    }

    // if $column isn't in $SEARCHABLE_TABLE_COLUMNS[$table],
    // then we need to tell the user we can't proceed with their request
    return response()->json([ 'error' => 'Illegal column name: '.$column ], 400);
}

// if $table isn't a key in $SEARCHABLE_TABLE_COLUMNS,
// then we need to tell the user we can't proceed with their request
return response()->json([ 'error' => 'Illegal table name: '.$table ], 400);

Me disculpo por el código PHP específico de Laravel, pero lo dejaré porque creo que puedes leerlo como pseudocódigo. la parte importante son los dos if declaraciones que se ejecutan sincrónicamente.

array_key_exists() y in_array() son funciones PHP.

fuente:

Lo bueno del algoritmo que mostré arriba es que puedes hacer un punto final REST como GET /in-use/{table}/{column}/{value} (donde table, columny value son variables).

Podrías tener:

$SEARCHABLE_TABLE_COLUMNS = [
    'accounts' => [ 'account_name', 'phone', 'business_email' ],
    'users' => [ 'email' ],
];

y luego podrías hacer solicitudes GET como:

GET /in-use/accounts/account_name/Bob's Drywall (es posible que deba codificar uri la última parte, pero generalmente no)

GET /in-use/accounts/phone/888-555-1337

GET /in-use/users/email/alice@bob.com

Note también que nadie puede hacer:

GET /in-use/users/password/dogmeat1337 porque password no aparece en su lista de columnas permitidas para user.

Buena suerte en tu viaje.

  • No tengo idea de qué tiene que ver esto con la pregunta, pero eché un vistazo y: realmente espero que NUNCA uses datos dinámicos en $SEARCHABLE_TABLE_COLUMNS! Esto pide a gritos una inyección, no importa si hay un “generador de consultas de marco ultra seguro” entre los que intenta enmascarar y filtrar cadenas de tablas y columnas. En la tabla final y las cadenas de columnas no se pueden agregar a través de un marcador de posición (declaraciones preparadas) y deben insertarse directamente como SELECT ... FROM {$table} WHERE {$column} = :placeholder ..... Ofc depende de los adaptadores (mysql, mongo, …) ¡PERO ese no es un argumento para salvarse! Por favor, lista estática o sin lista =)

    – algodón

    18 de junio de 2019 a las 11:43

¿Ha sido útil esta solución?