PHP matriz eliminar por valor (no clave)


886

Tengo una matriz PHP de la siguiente manera:

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

Quiero eliminar el elemento que contiene el valor $del_val(por ejemplo, $del_val=401), pero no sé su clave. Esto podría ayudar: cada valor solo puede estar allí una vez .

Estoy buscando la función más simple para realizar esta tarea, por favor.


1
@ Adam Strudwick Pero si tiene muchas eliminaciones en esta matriz, ¿sería mejor repetirla una vez y hacer que su clave sea igual que el valor?
dzona


Respuestas:


1566

Usando array_search()y unset, intente lo siguiente:

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

array_search()devuelve la clave del elemento que encuentra, que puede usarse para eliminar ese elemento de la matriz original usando unset(). Volverá FALSEen caso de falla, sin embargo, puede devolver un valor falso y en caso de éxito (su clave puede ser, 0por ejemplo), razón por la cual se utiliza el !==operador de comparación estricto .

La if()declaración verificará si array_search()devolvió un valor y solo realizará una acción si lo hizo.


14
¿$ Messages = array_diff ($ messages, array ($ del_val)) también funcionaría? ¿Sería mejor en rendimiento?
Adam Strudwick

99
@ Adam ¿Por qué no probarlo? Mi sensación es que array_diff()sería más lenta, ya que está comparando dos matrices, no simplemente buscar a través de uno como array_search().
Bojangles

22
Aunque esto es válido, debe evitar asignar valores en declaraciones como esa. Solo te meterá en problemas.
adlawson

17
¿Y si $keyes así 0?
evan

16
Si el valor que está buscando tiene una clave 0o cualquier otro valor de falsey, no lo desarmará y su código no funcionará. Deberías probarlo $key === false. (edit- lo tienes)
evan

674

Bueno, eliminar un elemento de la matriz es básicamente establecer la diferencia con un elemento.

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

Se generaliza muy bien, puede eliminar tantos elementos como desee al mismo tiempo, si lo desea.

Descargo de responsabilidad: tenga en cuenta que mi solución produce una nueva copia de la matriz mientras mantiene intacta la anterior en contraste con la respuesta aceptada que muta. Elige el que necesitas.


32
esto solo funciona para objetos que se pueden convertir en una cadena
nischayn22

77
Parece que recibo un 'Error de análisis' por decir [$element]que en su array($element)lugar lo usé . No es gran cosa, pero solo quería que cualquiera que tuviera un problema similar supiera que no estaban solos
Angad

8
Claro, he asumido que PHP 5.4 ahora es mayoritariamente para eliminar la antigua notación. Gracias por el comentario.
Rok Kralj

22
Vale la pena señalar que, por alguna razón, se array_diffusa (string) $elem1 === (string) $elem2como su condición de igualdad, no $elem1 === $elem2como se podría esperar. El problema señalado por @ nischayn22 es una consecuencia de esto. Si desea que algo se use como una función de utilidad que funcione para conjuntos de elementos arbitrarios (que podrían ser objetos), la respuesta de Bojangle podría ser mejor por este motivo.
Mark Amery el

44
También tenga en cuenta que este método realiza una clasificación interna para cada argumento array_diff()y, por lo tanto, empuja el tiempo de ejecución hasta O (n lg n) desde O (n).
Ja͢ck

115

Una forma interesante es mediante el uso de array_keys():

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

La array_keys()función toma dos parámetros adicionales para devolver solo claves para un valor particular y si se requiere una verificación estricta (es decir, usar === para la comparación).

Esto también puede eliminar múltiples elementos de la matriz con el mismo valor (por ejemplo [1, 2, 3, 3, 4]).


3
@ blasteralfredΨ Una búsqueda lineal es O (n); No estoy seguro de por qué parece pensar que es un problema.
Ja͢ck

1
Sí, esto es efectivo para seleccionar múltiples elementos / claves de la matriz.
Oki Erie Rinaldi

3
Esto es lo mejor para las matrices que pueden no contener todos los valores únicos.
Derokorian

El problema es que deja el índice de las teclas sin clasificar: [0] - a, [2] - b (el [1] se ha ido pero la matriz todavía lo pierde)
Rodniko

3
@Rodniko en cuyo caso también necesitarías array_values(); las teclas restantes todavía están en el mismo orden, así que técnicamente no está "sin clasificar"
Ja͢ck

55

Si sabe con certeza que su matriz contendrá solo un elemento con ese valor, puede hacer

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

Sin embargo, si su valor puede aparecer más de una vez en su matriz, puede hacer esto

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

Nota: La segunda opción solo funciona para PHP5.3 + con cierres


41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);

11
Esto solo funciona cuando su matriz no contiene valores duplicados que no sean los que está tratando de eliminar.
jberculo

2
@jberculo y, a veces, eso es exactamente lo que necesitas, en algunos casos me ahorra hacer una matriz única en él
DarkMukke

Tal vez, pero usaría funciones específicamente diseñadas para hacer eso, en lugar de ser solo un efecto secundario afortunado de una función que básicamente se usa y está destinada a otra cosa. También haría que su código sea menos transparente.
jberculo

El mensaje dice "cada valor solo puede estar allí una vez", esto debería funcionar. Hubiera sido bueno si el póster hubiera usado los nombres de las variables inteligentes y hubiera agregado un poco de explicación
Raatje

2
aparentemente esto es más rápido en comparación con la solución seleccionada, hice una pequeña evaluación comparativa.
AMB

28

Echa un vistazo al siguiente código:

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

Tu puedes hacer:

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

Y eso te dará esta matriz:

array('nice_item', 'another_liked_item')

1
Para las matrices asociativas, debe usar array_diff_assoc ()
theCodeMachine el

55
¿Cómo es esto diferente a esta respuesta ?
random_user_name

26

La mejor manera es array_splice

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

Reason for Best está aquí en http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/


44
Esto no funcionará en matrices asociativas y matrices que tienen huecos en sus claves, por ejemplo [1, 2, 4 => 3].
Ja͢ck

No, lo siento, esto funcionará. Lea el artículo que he proporcionado enlace
Airy

44
No lo hará. Considere la variedad de mi comentario anterior; después de usar su código para eliminar el valor 3, la matriz será [1, 2, 3]; en otras palabras, el valor no fue eliminado. Para ser claros, no digo que falle en todos los escenarios, solo en este.
Ja͢ck

1
array_splice es el mejor método, unset no ajustará los índices de la matriz después de eliminar
Raaghu

21

O simplemente, de forma manual:

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

Este es el más seguro de ellos porque tienes control total sobre tu matriz


1
Usar en array_splice()lugar de unset()reordenará los índices de matriz también, lo que podría ser mejor en este caso.
Daniele Orlando

20

Mediante el siguiente código, los valores repetitivos se eliminarán de los mensajes $.

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


3
Votado a favor. Ya estaba entre las otras respuestas, pero lo dices mejor manteniéndolo simple, como lo has hecho. La respuesta es simplemente "array_diff"
ghbarratt

1
Parece simple pero cambia la complejidad de O (n) a O (n lg n). Entonces, es más complejo de hecho;)
Krzysztof Przygoda

20

Si tiene PHP 5.3+, existe el código de una línea:

$array = array_filter($array, function ($i) use ($value) { return $i !== $value; }); 

¿Estás seguro? Ese cierre no tiene acceso $value, por lo que realmente debe colocarse en una mini clase para que pueda acceder $valuedentro del cierre ...
random_user_name

@cale_b, he actualizado el ejemplo. También aquí está la referencia: php.net/manual/en/functions.anonymous.php
David Lin

3
También podría escribir toda su base de código en una línea si llama a este "código de una línea"
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);

Salida

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


2
No estoy seguro de si esto es más rápido ya que esta solución involucra múltiples llamadas a funciones.
Julian Paolo Dayag

13

tu puedes hacer:

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

Explicación : elimine el elemento que tiene la clave 401después de voltear la matriz.


Tienes que tener mucho cuidado si quieres preservar el estado. porque todo el código futuro tendrá que tener valores en lugar de claves.
saadlulu

1
@saadlulu $ messages array no se volteará ya que array_flip () no afecta a la matriz original, por lo que la matriz resultante después de aplicar la línea anterior será la misma, excepto que se eliminará el resultado no deseado.
Qurashi

2
no estoy seguro si esto es correcto, ¿qué pasa si hay varios elementos con el valor de 401?
Zippp

Esto aún conservará las claves.
Szabolcs Páll

8

Para eliminar varios valores, pruebe este:

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

6

Tomó prestada la lógica de subrayar.JS _.reject y creó dos funciones (¡la gente prefiere las funciones!)

array_reject_value: esta función simplemente rechaza el valor especificado (también funciona para 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: esta función simplemente rechaza el método invocable (funciona para 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;
}

Entonces, en nuestro ejemplo actual, podemos usar las funciones anteriores de la siguiente manera:

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

o incluso mejor: (ya que esto nos da una mejor sintaxis para usar como el array_filter )

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

Lo anterior se puede usar para cosas más complicadas, como digamos que nos gustaría eliminar todos los valores que son mayores o iguales a 401, simplemente podríamos hacer esto:

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

1
¿No es este filtro de reinvención? php.net/manual/en/function.array-filter.php
Richard Duerr

Si de hecho. Como ya digo en la publicación "o incluso mejor: (ya que esto nos da una mejor sintaxis para usar como el array_filter)". A veces, realmente solo necesita que la función rechace como subrayado y es realmente lo opuesto al filtro (y necesita obtenerlo con el menor código posible). Esto es lo que están haciendo las funciones. Esta es una manera simple de rechazar valores.
John Skoumbourdis

6
$array = array("apple", "banana",'mango');
$array = array_filter($array, function($v) { return $v != "apple"; });

Pruebe esto, esta es la mejor y más rápida forma de eliminar elementos por valor


5

La respuesta de @Bojangles me ayudó. Gracias.

En mi caso, la matriz podría ser asociativa o no, así que agregué la siguiente función

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
 }

}

Saludos



4

La respuesta aceptada convierte la matriz en una matriz asociativa, por lo tanto, si desea mantenerla como una matriz no asociativa con la respuesta aceptada, es posible que también deba usarla array_values.

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

La referencia está aquí


4

Según su requisito, " cada valor solo puede estar allí por una vez " si solo está interesado en mantener valores únicos en su matriz, entonces elarray_unique() podría ser lo que está buscando.

Entrada:

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

Resultado:

array(2) {
  [0] => int(4)
  [2] => string(1) "3"
}

4

Si los valores que desea eliminar están o pueden estar en una matriz. Use la función array_diff . Parece funcionar muy bien para cosas como esta.

array_diff

$arrayWithValuesRemoved = array_diff($arrayOfData, $arrayOfValuesToRemove);

1
¿Cómo es esto diferente a esta respuesta ?
random_user_name

4

Sé que esto no es eficiente en absoluto, pero es simple, intuitivo y fácil de leer.
Entonces, si alguien está buscando una solución no tan elegante que se pueda extender para trabajar con más valores o condiciones más específicas ... aquí hay un código 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

4

Obtenga la clave de matriz con array_search().


2
¿Cómo elimino el valor IF y solo si lo encuentro con array_search?
Adam Strudwick

3
$ k = array_search ($ aguja, $ haystack, verdadero); if ($ k! == false) {unset ($ haystack [$ k]); }
evan

3

Si no conoce su clave, significa que no importa.

Puede colocar el valor como clave, significa que encontrará el valor instantáneamente. Mejor que usar la búsqueda en todos los elementos una y otra vez.

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

unset($messages[3]); // no search needed

Solo funciona para objetos que se pueden convertir en una cadena.
Emile Bergeron

2

Una línea usando el oroperador:

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

2

puedes referir esta URL : para la función

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

Entonces la salida debería ser,

array(2) {
  ["red"]=>
  int(2)
  ["purple"]=>
  int(4)
}


1

Creo que la forma más sencilla sería utilizar una función con un bucle 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 salida será:

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

1

Con PHP 7.4 usando funciones de flecha:

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

Para mantenerlo en una matriz no asociativa, envuélvalo con array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.