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.

Adam Strudwick
fuente
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
Misma pregunta: stackoverflow.com/questions/1883421/…
Eric Lavoie
posible duplicado de PHP Eliminar un elemento de una matriz
Alex

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.

Bojangles
fuente
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.

Rok Kralj
fuente
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]).

Jack
fuente
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

adlawson
fuente
41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);
Rmannn
fuente
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')
theCodeMachine
fuente
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/

Aireado
fuente
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

Victor Priceputu
fuente
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));

Syed Abidur Rahman
fuente
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; }); 
David Lin
fuente
¿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 )

tttony
fuente
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.

Qurashi
fuente
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]);
}
Rajendra Khabiya
fuente
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;
});
John Skoumbourdis
fuente
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

Paras Raiyani
fuente
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

angeltcho
fuente
4

código de línea único (gracias a array_diff () ), use lo siguiente:

$messages = array_diff($messages, array(401));
Estrella
fuente
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í

SaidbakR
fuente
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"
}
Mohd Abdul Mujib
fuente
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);
usuario1518699
fuente
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
d.raev
fuente
4

Obtenga la clave de matriz con array_search().

evan
fuente
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
Ismael
fuente
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]);
Eric
fuente
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)
}
manish1706
fuente
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)
}
algo
fuente
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));
Roy
fuente