web-dev-qa-db-fra.com

Vérifier si les éléments d’un tableau sont dans un autre tableau dans PHP

J'ai deux tableaux dans PHP comme suit:

Personnes:

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

criminels recherchés:

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
)

Comment puis-je vérifier si tous des éléments Personnes sont dans les criminels recherchés tableau?

Dans cet exemple, il devrait retourner true car 20 est dans criminels recherchés .

Merci d'avance.

107
Philip Morton

Vous pouvez utiliser array_intersect() .

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

Il y a peu d'inconvénients à utiliser array_intersect () et count () (au lieu de empty).

Par exemple:

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

si 'vide' n'est pas le meilleur choix, qu'en est-il de ceci:

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

ou

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

Ce code n'est pas valide car vous ne pouvez transmettre que des variables dans des constructions de langage. empty() est une construction de langage.

Vous devez le faire en deux lignes:

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

Test de performance pour 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;

Voici les résultats:

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 est au moins 5 fois plus rapide. Notez que nous "cassons" dès qu'un résultat est trouvé.

16
Frank Forte

Voici une façon dont je le fais après avoir recherché pendant un moment. Je voulais créer un endpoint d'API Laravel) qui vérifie si un champ est "en cours d'utilisation". Par conséquent, les informations importantes sont les suivantes: 1) quelle table de base de données? 2) quelle colonne de base de données? et 3) y a-t-il une valeur dans cette colonne qui correspond aux termes de la recherche?

Sachant cela, nous pouvons construire notre tableau associatif:

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

Ensuite, nous pouvons définir nos valeurs que nous vérifierons:

$table = 'users';
$column = 'email';
$value = '[email protected]';

Ensuite, nous pouvons utiliser array_key_exists() et in_array() pour exécuter un combo à un, deux étapes, puis agir sur la condition truthy:

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

Je m'excuse pour le code spécifique à Laravel PHP, mais je vais le laisser car je pense que vous pouvez le lire sous forme de pseudo-code. La partie importante sont les deux instructions if exécutées de manière synchrone.

array_key_exists() et in_array() sont PHP fonctions.

la source:

La bonne chose à propos de l’algorithme que j’ai montré ci-dessus est que vous pouvez créer un noeud final REST tel que GET /in-use/{table}/{column}/{value}) (Où table, column et value sont des variables).

Tu aurais pu:

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

et ensuite vous pouvez faire des requêtes GET telles que:

GET /in-use/accounts/account_name/Bob's Drywall (Vous aurez peut-être besoin d'encoder la dernière partie, mais généralement pas)

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

GET /in-use/users/email/[email protected]

Notez également que personne ne peut faire:

GET /in-use/users/password/dogmeat1337 Car password ne figure pas dans votre liste de colonnes autorisées pour user.

Bonne chance pour ton voyage.

1
agm1984

Vous pouvez également utiliser in_array comme suit:

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

Bien que array_intersect soit certainement plus pratique à utiliser, il n’est pas vraiment supérieur en termes de performances. J'ai aussi créé ce script:

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

Ensuite, j'ai exécuté les deux extraits respectivement à: http://3v4l.org/WGhO7/perf#tabs et http://3v4l.org/g1Hnu/perf#tabs et vérifié les performances de chacun. Ce qui est intéressant, c’est que le temps CPU total, c’est-à-dire le temps utilisateur et le temps système, est identique pour PHP 5.5 et que la mémoire est identique. Le temps de calcul total sous PHP 5.4 est moins pour in_array que pour array_intersect, même si ce n'est que marginalement.

1
slevy1