Suppression de tableau PHP par valeur (pas par clé)

886

J'ai un tableau PHP comme suit:

$messages = [312, 401, 1599, 3, ...];

Je veux supprimer l'élément contenant la valeur $del_val(par exemple, $del_val=401), mais je ne connais pas sa clé. Cela pourrait aider: chaque valeur ne peut être présente qu'une seule fois .

Je recherche la fonction la plus simple pour effectuer cette tâche, s'il vous plaît.

Adam Strudwick
la source
1
@Adam Strudwick Mais si vous avez de nombreuses suppressions sur ce tableau, serait-il préférable de l'itérer une fois et de rendre sa clé identique à value?
dzona
Même question: stackoverflow.com/questions/1883421/…
Eric Lavoie
double possible de PHP Supprimer un élément d'un tableau
Alex

Réponses:

1566

À l'aide de array_search()et unset, essayez ce qui suit:

if (($key = array_search($del_val, $messages)) !== false) {
    unset($messages[$key]);
}

array_search()renvoie la clé de l'élément qu'il trouve, qui peut être utilisée pour supprimer cet élément du tableau d'origine à l'aide de unset(). Il retournera FALSEen cas d'échec, mais il peut retourner une valeur faux-y en cas de succès (votre clé peut être 0par exemple), c'est pourquoi l' !==opérateur de comparaison strict est utilisé.

L' if()instruction vérifie si array_search()une valeur a été renvoyée et n'exécute une action que si elle l'a fait.

Bojangles
la source
14
Est-ce que $ messages = array_diff ($ messages, array ($ del_val)) fonctionnerait aussi? Serait-ce mieux dans les performances?
Adam Strudwick
9
@Adam Pourquoi ne pas le tester? Mon sentiment est que ce array_diff()serait plus lent car il compare deux tableaux, pas simplement en recherchant un comme array_search().
Bojangles
22
Même si cela est valide, vous devez éviter d'attribuer des valeurs dans des instructions comme celle-ci. Cela ne vous causera que des ennuis.
adlawson
17
Que faire si $keyest 0?
evan
16
Si la valeur que vous recherchez a une clé 0ou toute autre valeur de falsey, elle ne débloquera pas la valeur et votre code ne fonctionnera pas. Vous devriez tester $key === false. (
modifier
674

Eh bien, la suppression d'un élément du tableau est fondamentalement juste la différence avec un élément.

array_diff( [312, 401, 15, 401, 3], [401] ) // removing 401 returns [312, 15, 3]

Il généralise bien, vous pouvez supprimer autant d'éléments que vous le souhaitez en même temps, si vous le souhaitez.

Avertissement: Notez que ma solution produit une nouvelle copie du tableau tout en conservant l'ancien contrairement à la réponse acceptée qui mute. Choisissez celui dont vous avez besoin.

Rok Kralj
la source
32
cela ne fonctionne que pour les objets qui peuvent être convertis en chaîne
nischayn22
7
Il semble que j'obtienne une «erreur d'analyse» pour avoir dit que [$element]j'ai utilisé à la array($element)place. Pas de biggie, mais je voulais juste que toute personne ayant un problème similaire sache qu'elle n'était pas seule
Angad
8
Bien sûr, j'ai supposé que PHP 5.4 est désormais majoritaire pour abandonner l'ancienne notation. Merci pour la remarque.
Rok Kralj
22
Il convient de noter que pour une raison quelconque, il est array_diffutilisé (string) $elem1 === (string) $elem2comme condition d'égalité, et non $elem1 === $elem2comme on pourrait s'y attendre. Le problème signalé par @ nischayn22 en est la conséquence. Si vous voulez quelque chose à utiliser comme fonction utilitaire qui fonctionnera pour des tableaux d'éléments arbitraires (qui pourraient être des objets), la réponse de Bojangle pourrait être meilleure pour cette raison.
Mark Amery
4
Notez également que cette méthode effectue un tri en interne pour chaque argument array_diff()et déplace ainsi le runtime jusqu'à O (n lg n) de O (n).
Ja͢ck
115

Une façon intéressante consiste à utiliser array_keys():

foreach (array_keys($messages, 401, true) as $key) {
    unset($messages[$key]);
}

La array_keys()fonction prend deux paramètres supplémentaires pour renvoyer uniquement les clés pour une valeur particulière et si une vérification stricte est requise (c'est-à-dire en utilisant === pour la comparaison).

Cela peut également supprimer plusieurs éléments de tableau avec la même valeur (par exemple [1, 2, 3, 3, 4]).

Jack
la source
3
@ blasteralfredΨ Une recherche linéaire est O (n); Je ne sais pas pourquoi vous semblez penser que c'est un problème.
Ja͢ck
1
Oui, cela est efficace pour sélectionner plusieurs éléments / clés de tableau.
Oki Erie Rinaldi
3
C'est le meilleur pour les tableaux qui peuvent ne pas contenir toutes les valeurs uniques.
Derokorian
Le problème est qu'il laisse l'index des clés sous tri: [0] - a, [2] - b (le [1] est parti mais le tableau le manque toujours)
Rodniko
3
@Rodniko auquel cas vous auriez également besoin array_values(); les touches restantes sont toujours dans le même ordre, donc techniquement ce n'est pas "non trié"
Ja͢ck
55

Si vous savez pour sûr que votre tableau ne contiendra qu'un seul élément avec cette valeur, vous pouvez le faire

$key = array_search($del_val, $array);
if (false !== $key) {
    unset($array[$key]);
}

Si, cependant, votre valeur peut apparaître plusieurs fois dans votre tableau, vous pouvez le faire

$array = array_filter($array, function($e) use ($del_val) {
    return ($e !== $del_val);
});

Remarque: La deuxième option ne fonctionne que pour PHP5.3 + avec fermetures

adlawson
la source
41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);
Rmannn
la source
11
Cela ne fonctionne que lorsque votre tableau ne contient pas de valeurs en double autres que celles que vous essayez de supprimer.
jberculo
2
@jberculo et parfois exactement ce dont vous avez besoin, dans certains cas, cela me permet d'économiser un tableau unique dessus
DarkMukke
Peut-être, mais j'utiliserais des fonctions spécialement conçues pour cela, au lieu d'être juste un effet secondaire chanceux d'une fonction qui est essentiellement utilisée et destinée à autre chose. Cela rendrait également votre code moins transparent.
jberculo
Le message indique que "chaque valeur ne peut être présente qu'une seule fois", cela devrait fonctionner. Cela aurait été bien si l'affiche avait utilisé les noms des variables smae et ajouté une petite explication
Raatje
2
apparemment, c'est le plus rapide par rapport à la solution sélectionnée, j'ai fait une petite analyse comparative.
AMB
28

Jetez un œil au code suivant:

$arr = array('nice_item', 'remove_me', 'another_liked_item', 'remove_me_also');

Tu peux faire:

$arr = array_diff($arr, array('remove_me', 'remove_me_also'));

Et cela vous donnera ce tableau:

array('nice_item', 'another_liked_item')
theCodeMachine
la source
1
Pour les tableaux associatifs, vous devez utiliser array_diff_assoc ()
theCodeMachine
5
En quoi est-ce différent de cette réponse ?
random_user_name
26

La meilleure façon est array_splice

array_splice($array, array_search(58, $array ), 1);

Reason for Best est ici sur http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/

Airy
la source
4
Cela ne fonctionnera pas sur les tableaux associatifs et les tableaux qui ont des lacunes dans leurs clés, par exemple [1, 2, 4 => 3].
Ja͢ck
Non désolé, cela fonctionnera. Veuillez lire l'article que j'ai fourni le lien
Airy
4
Ce ne sera pas le cas. Considérez le tableau de mon commentaire ci-dessus; après avoir utilisé votre code pour supprimer la valeur 3, le tableau sera [1, 2, 3]; en d'autres termes, la valeur n'a pas été supprimée. Pour être clair, je ne dis pas qu'il échoue dans tous les scénarios, juste celui-ci.
Ja͢ck
1
array_splice est la meilleure méthode, unset n'ajustera pas les index de tableau après la suppression
Raaghu
21

Ou simplement, de manière manuelle:

foreach ($array as $key => $value){
    if ($value == $target_value) {
        unset($array[$key]);
    }
}

C'est le plus sûr d'entre eux car vous avez un contrôle total sur votre baie

Victor Priceputu
la source
1
Utiliser array_splice()au lieu de unset()réorganisera également les index de tableau, ce qui pourrait être mieux dans ce cas.
Daniele Orlando
20

Par le code suivant, les valeurs répétitives seront supprimées des messages $.

$messages = array_diff($messages, array(401));

Syed Abidur Rahman
la source
3
Voté. C'était déjà parmi les autres réponses mais vous le dites mieux en restant simple, comme vous l'avez fait. La réponse est simplement "array_diff"
ghbarratt
1
Semble simple, mais il change la complexité de O (n) à O (n lg n). Donc, c'est plus complexe en fait;)
Krzysztof Przygoda
20

Si vous avez PHP 5.3+, il y a le code d'une ligne:

$array = array_filter($array, function ($i) use ($value) { return $i !== $value; }); 
David Lin
la source
Êtes-vous sûr? Cette fermeture n'a pas accès à $value, donc vraiment elle doit être mise dans une mini-classe pour que vous puissiez y accéder $valuedans la fermeture ....
random_user_name
@cale_b, j'ai mis à jour l'exemple. Voici également la référence: php.net/manual/en/functions.anonymous.php
David Lin
3
Vous pourriez aussi bien écrire l'intégralité de votre base de code sur une seule ligne si vous appelez ce "code à une ligne"
Milan Simek
16
function array_remove_by_value($array, $value)
{
    return array_values(array_diff($array, array($value)));
}

$array = array(312, 401, 1599, 3);

$newarray = array_remove_by_value($array, 401);

print_r($newarray);

Production

Array ( [0] => 312 [1] => 1599 [2] => 3 )

tttony
la source
2
Je ne sais pas si c'est plus rapide car cette solution implique plusieurs appels de fonction.
Julian Paolo Dayag
13

tu peux faire:

unset($messages[array_flip($messages)['401']]);

Explication : supprimez l'élément qui possède la clé 401après avoir inversé le tableau.

Qurashi
la source
Vous devez être très prudent si vous voulez préserver l'état. car tout le futur code devra avoir des valeurs au lieu de clés.
saadlulu
1
Le tableau @saadlulu $ messages ne sera pas retourné car array_flip () n'affecte pas le tableau d'origine, donc le tableau résultant après application de la ligne précédente sera le même sauf que le résultat indésirable sera supprimé.
Qurashi
2
Je ne sais pas si c'est correct, que se passe-t-il s'il y a plusieurs éléments avec la valeur de 401?
Zippp
Cela conservera toujours les clés.
Szabolcs Páll
8

Pour supprimer plusieurs valeurs, essayez celle-ci:

while (($key = array_search($del_val, $messages)) !== false) 
{
    unset($messages[$key]);
}
Rajendra Khabiya
la source
6

Emprunté la logique de underscore.JS _.reject et créé deux fonctions (les gens préfèrent les fonctions !!)

array_reject_value: Cette fonction rejette simplement la valeur spécifiée (fonctionne également pour PHP4,5,7)

function array_reject_value(array &$arrayToFilter, $deleteValue) {
    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if ($value !== $deleteValue) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

array_reject: Cette fonction rejette simplement la méthode appelable (fonctionne pour PHP> = 5.3)

function array_reject(array &$arrayToFilter, callable $rejectCallback) {

    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if (!$rejectCallback($value, $key)) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

Ainsi, dans notre exemple actuel, nous pouvons utiliser les fonctions ci-dessus comme suit:

$messages = [312, 401, 1599, 3, 6];
$messages = array_reject_value($messages, 401);

ou encore mieux: (car cela nous donne une meilleure syntaxe à utiliser comme celle de array_filter )

$messages = [312, 401, 1599, 3, 6];
$messages = array_reject($messages, function ($value) {
    return $value === 401;
});

Ce qui précède peut être utilisé pour des choses plus compliquées comme disons que nous aimerions supprimer toutes les valeurs supérieures ou égales à 401, nous pourrions simplement le faire:

$messages = [312, 401, 1599, 3, 6];
$greaterOrEqualThan = 401;
$messages = array_reject($messages, function ($value) use $greaterOrEqualThan {
    return $value >= $greaterOrEqualThan;
});
John Skoumbourdis
la source
1
Ce filtre n'est-il pas réinventé? php.net/manual/en/function.array-filter.php
Richard Duerr
Oui en effet. Comme je le dis déjà dans l'article "ou encore mieux: (car cela nous donne une meilleure syntaxe à utiliser comme celle de array_filter)". Parfois, vous avez juste besoin que la fonction rejette en tant que trait de soulignement et c'est vraiment juste l'opposé du filtre (et vous devez l'obtenir avec le moins de code possible). C'est ce que font les fonctions. Il s'agit d'un moyen simple de rejeter des valeurs.
John Skoumbourdis
6
$array = array("apple", "banana",'mango');
$array = array_filter($array, function($v) { return $v != "apple"; });

Essayez ceci, c'est le moyen le meilleur et le plus rapide pour supprimer l'élément par valeur

Paras Raiyani
la source
5

La réponse @Bojangles m'a aidé. Je vous remercie.

Dans mon cas, le tableau peut être associatif ou non, j'ai donc ajouté la fonction suivante

function test($value, $tab) {

 if(($key = array_search($value, $tab)) !== false) {
    unset($tab[$key]); return true;

 } else if (array_key_exists($value, $tab)){
        unset($tab[$value]); return true;

 } else {
    return false; // the $value is not in the array $tab
 }

}

Cordialement

angeltcho
la source
4

code simple (grâce à array_diff () ), utilisez ce qui suit:

$messages = array_diff($messages, array(401));
Étoile
la source
4

La réponse acceptée convertit le tableau en tableau associatif, donc, si vous souhaitez le conserver en tant que tableau non associatif avec la réponse acceptée, vous devrez peut-être array_valueségalement l' utiliser .

if(($key = array_search($del_val, $messages)) !== false) {
    unset($messages[$key]);
    $arr = array_values($messages);
}

La référence est ici

SaidbakR
la source
4

Selon votre exigence " chaque valeur ne peut être là que pour une fois " si vous êtes simplement intéressé à conserver des valeurs uniques dans votre tableau, alors c'est array_unique()peut-être ce que vous recherchez.

Contribution:

$input = array(4, "4", "3", 4, 3, "3");
$result = array_unique($input);
var_dump($result);

Résultat:

array(2) {
  [0] => int(4)
  [2] => string(1) "3"
}
Mohd Abdul Mujib
la source
4

Si les valeurs que vous souhaitez supprimer sont ou peuvent être dans un tableau. Utilisez la fonction array_diff . Semble fonctionner très bien pour des choses comme ça.

array_diff

$arrayWithValuesRemoved = array_diff($arrayOfData, $arrayOfValuesToRemove);
user1518699
la source
1
En quoi est-ce différent de cette réponse ?
random_user_name
4

Je sais que ce n'est pas efficace du tout mais c'est simple, intuitif et facile à lire.
Donc, si quelqu'un cherche une solution pas si sophistiquée qui peut être étendue pour fonctionner avec plus de valeurs ou des conditions plus spécifiques .. voici un code simple:

$result = array();
$del_value = 401;
//$del_values = array(... all the values you don`t wont);

foreach($arr as $key =>$value){
    if ($value !== $del_value){
        $result[$key] = $value;
    }

    //if(!in_array($value, $del_values)){
    //    $result[$key] = $value;
    //}

    //if($this->validete($value)){
    //      $result[$key] = $value;
    //}
}

return $result
d.raev
la source
4

Obtenez la clé du tableau avec array_search().

evan
la source
2
Comment supprimer la valeur IF et uniquement si je la trouve avec array_search?
Adam Strudwick
3
$ k = array_search ($ needle, $ haystack, true); if ($ k! == false) {unset ($ haystack [$ k]); }
evan
3

Si vous ne connaissez pas sa clé, cela signifie que cela n'a pas d'importance.

Vous pouvez placer la valeur comme clé, cela signifie qu'elle trouvera instantanément la valeur. Mieux que d'utiliser la recherche dans tous les éléments encore et encore.

$messages=array();   
$messages[312] = 312;    
$messages[401] = 401;   
$messages[1599] = 1599;   
$messages[3] = 3;    

unset($messages[3]); // no search needed
Ismael
la source
Fonctionne uniquement pour les objets qui peuvent être convertis en chaîne.
Emile Bergeron
2

Un one-liner utilisant l' oropérateur:

($key = array_search($del_val, $messages)) !== false or unset($messages[$key]);
Eric
la source
2

vous pouvez référer cette URL : pour la fonction

array-diff-key()

<?php
$array1 = array('blue'  => 1, 'red'  => 2, 'green'  => 3, 'purple' => 4);
$array2 = array('green' => 5, 'blue' => 6, 'yellow' => 7, 'cyan'   => 8);

var_dump(array_diff_key($array1, $array2));
?>

La sortie devrait alors être,

array(2) {
  ["red"]=>
  int(2)
  ["purple"]=>
  int(4)
}
manish1706
la source
1

Je pense que la manière la plus simple serait d'utiliser une fonction avec une boucle foreach:

//This functions deletes the elements of an array $original that are equivalent to the value $del_val
//The function works by reference, which means that the actual array used as parameter will be modified.

function delete_value(&$original, $del_val)
{
    //make a copy of the original, to avoid problems of modifying an array that is being currently iterated through
    $copy = $original;
    foreach ($original as $key => $value)
    {
        //for each value evaluate if it is equivalent to the one to be deleted, and if it is capture its key name.
        if($del_val === $value) $del_key[] = $key;
    };
    //If there was a value found, delete all its instances
    if($del_key !== null)
    {
        foreach ($del_key as $dk_i)
        {
            unset($original[$dk_i]);
        };
        //optional reordering of the keys. WARNING: only use it with arrays with numeric indexes!
        /*
        $copy = $original;
        $original = array();
        foreach ($copy as $value) {
            $original[] = $value;
        };
        */
        //the value was found and deleted
        return true;
    };
    //The value was not found, nothing was deleted
    return false;
};

$original = array(0,1,2,3,4,5,6,7,4);
$del_val = 4;
var_dump($original);
delete_value($original, $del_val);
var_dump($original);

La sortie sera:

array(9) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(4)
}
array(7) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
}
algo
la source
1

Avec PHP 7.4 en utilisant les fonctions fléchées:

$messages = array_filter($messages, fn ($m) => $m != $del_val);

Pour le conserver dans un tableau non associatif, enveloppez-le avec array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
Roy
la source