Exclusão da matriz PHP por valor (não chave)

886

Eu tenho uma matriz PHP da seguinte maneira:

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

Quero excluir o elemento que contém o valor $del_val(por exemplo $del_val=401), mas não sei sua chave. Isso pode ajudar: cada valor pode estar lá apenas uma vez .

Estou procurando a função mais simples para executar esta tarefa, por favor.

Adam Strudwick
fonte
1
@ Adam Strudwick Mas se você tiver muitas exclusões nessa matriz, seria melhor iterá-la uma vez e fazer com que sua chave fosse igual ao valor?
dzona
Mesma pergunta: stackoverflow.com/questions/1883421/…
Eric Lavoie
duplicado posible de PHP Excluir um elemento de uma matriz
Alex

Respostas:

1566

Usando array_search()e unset, tente o seguinte:

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

array_search()retorna a chave do elemento encontrado, que pode ser usado para remover esse elemento da matriz original usando unset(). Ele retornará FALSEem caso de falha, mas poderá retornar um valor falso-y em caso de sucesso (sua chave pode ser, 0por exemplo), razão pela qual o !==operador de comparação estrita é usado.

A if()instrução verificará se array_search()um valor retornou e só executará uma ação se o fizer.

Bojangles
fonte
14
$ Messages = array_diff ($ messages, array ($ del_val)) também funcionaria? Seria melhor no desempenho?
Adam Strudwick
9
@ Adam Por que não testá-lo? Meu sentimento é que array_diff()seria mais lento, como é comparar duas matrizes, e não simplesmente pesquisar através de um como array_search().
Bojangles
22
Mesmo que isso seja válido, você deve evitar atribuir valores em declarações como essa. Isso só causará problemas.
adlawson
17
E se $keyfor 0?
quer
16
Se o valor que você está procurando tiver uma chave 0ou qualquer outro valor falsey, ele não desmarca o valor e seu código não funciona. Você deveria testar $key === false. (edit- você conseguiu)
evan
674

Bem, excluir um elemento da matriz é basicamente definir a diferença com um elemento.

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

Ele generaliza bem, você pode remover quantos elementos quiser ao mesmo tempo, se desejar.

Isenção de responsabilidade: observe que minha solução produz uma nova cópia da matriz, mantendo a antiga intacta, em contraste com a resposta aceita que sofre mutação. Escolha o que você precisa.

Rok Kralj
fonte
32
isso só funciona para objetos que podem ser convertidos para uma string
nischayn22
7
Parece que estou recebendo um 'Erro de análise' por dizer [$element]que usei array($element). Nada demais, mas alguém só queria que tinha um problema semelhante para saber que eles não estavam sozinhos
Angad
8
Claro, eu assumi que o PHP 5.4 agora é majoritário para descartar a notação antiga. Obrigado pela observação.
Rok Kralj
22
Vale a pena notar que, por algum motivo, array_diffusa (string) $elem1 === (string) $elem2como sua condição de igualdade, não $elem1 === $elem2como você poderia esperar. A questão apontada por @ nischayn22 é uma consequência disso. Se você deseja que algo use como uma função utilitária que funcione para matrizes de elementos arbitrários (que podem ser objetos), a resposta do Bojangle pode ser melhor por esse motivo.
Mark Amery
4
Observe também que esse método executa uma classificação internamente para cada argumento array_diff()e, portanto, estimula o tempo de execução até O (n lg n) de O (n).
Ja͢ck
115

Uma maneira interessante é usar array_keys():

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

A array_keys()função utiliza dois parâmetros adicionais para retornar apenas chaves para um valor específico e se é necessária uma verificação rigorosa (por exemplo, usando === para comparação).

Isso também pode remover vários itens da matriz com o mesmo valor (por exemplo [1, 2, 3, 3, 4]).

Ja͢ck
fonte
3
@ blasteralfredΨ Uma pesquisa linear é O (n); Não sei por que você acha que isso é um problema.
Jack
1
Sim, isso é eficaz para selecionar vários itens / chaves da matriz.
Oki Erie Rinaldi
3
É o melhor para matrizes que podem não conter todos os valores exclusivos.
Derokorian
O problema é que ele deixa o índice das chaves onsorted: [0] - a, [2] - b (a [1] é ido, mas a matriz ainda falta-)
Rodniko
3
@Rodniko; nesse caso, você precisaria array_values()também; as chaves restantes ainda estão na mesma ordem, porém, assim tecnicamente não é "indiferenciados"
Jack
55

Se você souber com certeza que sua matriz conterá apenas um elemento com esse valor, poderá fazer

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

Se, no entanto, seu valor puder ocorrer mais de uma vez em sua matriz, você poderá fazer isso

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

Nota: A segunda opção funciona apenas para PHP5.3 + com Closures

adlawson
fonte
41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);
Rmannn
fonte
11
Isso funciona apenas quando sua matriz não contém valores duplicados que não sejam os que você está tentando remover.
jberculo
2
@jberculo e às vezes isso exatamente o que você precisa, em alguns casos, salva-me fazer um único conjunto nele aswel
DarkMukke
Talvez, mas eu usaria funções projetadas especificamente para fazer isso, em vez de ser apenas um efeito colateral feliz de uma função que é basicamente usada e destinada a outra coisa. Isso também tornaria seu código menos transparente.
jberculo
A mensagem indica "cada valor pode estar lá apenas uma vez", isso deve funcionar. Teria sido bom se o cartaz tinha usado os nomes das variáveis smae embora e acrescentou um pouco explenation
Raatje
2
aparentemente isso é mais rápido em comparação com a solução selecionada, fiz pequenos testes comparativos.
AMB
28

Veja o seguinte código:

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

Você pode fazer:

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

E isso lhe dará essa matriz:

array('nice_item', 'another_liked_item')
theCodeMachine
fonte
1
Para matrizes associativas, você deve usar array_diff_assoc ()
theCodeMachine 15/10/2015
5
Como isso é diferente da resposta ?
random_user_name 20/09/16
26

A melhor maneira é array_splice

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

Razão para Melhor está aqui em http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/

Arejado
fonte
4
Isso não funcionará em matrizes associativas e matrizes com lacunas em suas chaves, por exemplo [1, 2, 4 => 3].
Ja͢ck
Desculpe, isso vai funcionar. Por favor, leia o artigo que eu forneci link
Airy
4
Não vai. Considere a matriz do meu comentário acima; depois que eu usar seu código para remover o valor 3, a matriz será [1, 2, 3]; em outras palavras, o valor não foi removido. Para ser claro, não estou dizendo que falha em todos os cenários, apenas neste.
21414 Jahck
1
array_splice é o melhor método, unset não irá ajustar os índices de matriz após a exclusão
Raaghu
21

Ou simplesmente, de maneira manual:

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

Este é o mais seguro deles, porque você tem controle total sobre sua matriz

Victor Priceputu
fonte
1
Usar em array_splice()vez de unset()reordenará os índices da matriz também, o que poderia ser melhor nesse caso.
Daniele Orlando
20

Pelo código a seguir, os valores repetitivos serão removidos das $ messages.

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

Syed Abidur Rahman
fonte
3
Up-vote. Já estava entre as outras respostas, mas você diz isso melhor, mantendo-o simples, como fez. A resposta é simplesmente "array_diff"
ghbarratt
1
Parece simples, mas altera a complexidade de O (n) para O (n lg n). Então, é mais complexo na verdade;)
Krzysztof Przygoda
20

Se você possui PHP 5.3+, existe o código de uma linha:

$array = array_filter($array, function ($i) use ($value) { return $i !== $value; }); 
David Lin
fonte
Você tem certeza? Que o fechamento não tem acesso a $value, então realmente tem que ser colocado em uma mini-aula, assim você pode acessar $valuedentro do fechamento ....
random_user_name
@cale_b, atualizei o exemplo. Também aqui está a ref: php.net/manual/en/functions.anonymous.php
David Lin
3
Você também pode escrever toda a sua base de código em uma linha se chamar esse "código de uma linha"
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);

Resultado

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

tttony
fonte
2
Não tenho certeza se isso é mais rápido, pois esta solução envolve várias chamadas de função.
Julian Paolo Dayag
13

você pode fazer:

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

Explicação : Exclua o elemento que possui a chave 401depois de virar a matriz.

Qurashi
fonte
Você precisa ter muito cuidado se quiser preservar o estado. porque todo o código futuro precisará ter valores em vez de chaves.
saadlulu
1
A matriz @saadlulu $ messages não será invertida, pois array_flip () não afeta a matriz original; portanto, a matriz resultante após a aplicação da linha anterior será a mesma, exceto que o resultado indesejado será removido.
Qurashi
2
não tenho certeza se isso está correto, e se houver vários elementos com o valor de 401?
Zippp 6/03/19
Isso ainda preservará as chaves.
Szabolcs Páll
8

Para excluir vários valores, tente este:

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

Emprestou a lógica de underscore.JS _.reject e criou duas funções (as pessoas preferem funções !!)

array_reject_value: Esta função está simplesmente rejeitando o valor especificado (também 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 função está simplesmente rejeitando o método que pode ser chamado (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;
}

Portanto, em nosso exemplo atual, podemos usar as funções acima, da seguinte maneira:

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

ou ainda melhor: (como isso nos dá uma sintaxe melhor para usar como a matriz array_filter )

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

O exemplo acima pode ser usado para coisas mais complicadas, como, digamos, que gostaríamos de remover todos os valores maiores ou iguais a 401. Podemos simplesmente fazer o seguinte:

$messages = [312, 401, 1599, 3, 6];
$greaterOrEqualThan = 401;
$messages = array_reject($messages, function ($value) use $greaterOrEqualThan {
    return $value >= $greaterOrEqualThan;
});
John Skoumbourdis
fonte
1
Este filtro não é reinventador? php.net/manual/en/function.array-filter.php
Richard Duerr
Sim, de fato. Como já estou dizendo no post "ou melhor ainda: (como isso nos dá uma sintaxe melhor para usar como a array_filter)". Às vezes, você realmente precisa rejeitar a função como sublinhado e isso é exatamente o oposto do filtro (e você precisa obtê-la com o mínimo de código possível). É isso que as funções estão fazendo. Essa é uma maneira simples de rejeitar valores.
John Skoumbourdis 25/10
6
$array = array("apple", "banana",'mango');
$array = array_filter($array, function($v) { return $v != "apple"; });

Tente isso, esta é a melhor e mais rápida maneira de remover elemento por valor

Paras Raiyani
fonte
5

A resposta @Bojangles me ajudou. Obrigado.

No meu caso, a matriz pode ser associativa ou não, então eu adicionei a seguinte função

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
 }

}

Saudações

angeltcho
fonte
4

código de liner único (graças a array_diff () ), use o seguinte:

$messages = array_diff($messages, array(401));
Estrela
fonte
4

A resposta aceita converte a matriz em matriz associativa; portanto, se você deseja mantê-la como uma matriz não associativa com a resposta aceita, talvez seja necessário usar array_valuestambém.

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

A referência está aqui

SaidbakR
fonte
4

Conforme sua exigência " cada valor pode estar lá apenas uma vez " se você estiver apenas interessado em manter valores exclusivos em sua matriz, então array_unique()pode ser o que você está procurando.

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
fonte
4

Se os valores que você deseja excluir estiverem ou puderem estar em uma matriz. Use o array_diff função . Parece funcionar muito bem para coisas assim.

array_diff

$arrayWithValuesRemoved = array_diff($arrayOfData, $arrayOfValuesToRemove);
user1518699
fonte
1
Como isso é diferente da resposta ?
Random_user_name 20/09/16
4

Sei que isso não é nada eficiente, mas é simples, intuitivo e fácil de ler.
Portanto, se alguém está procurando uma solução não tão sofisticada que possa ser estendida para trabalhar com mais valores ou condições mais específicas ... aqui está um código simples:

$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
fonte
4

Obtenha a chave da matriz com array_search().

evan
fonte
2
Como excluo o valor SE e somente se o encontrar com array_search?
Adam Strudwick 29/08
3
$ k = array_search ($ agulha, $ palheiro, verdadeiro); if ($ k! == false) {desabilitado ($ haystack [$ k]); }
evan
3

Se você não conhece sua chave, significa que não importa.

Você pode colocar o valor como chave, significa que ele encontrará o valor instantaneamente. Melhor do que usar a pesquisa em todos os elementos repetidamente.

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

unset($messages[3]); // no search needed
Ismael
fonte
Funciona apenas para objetos que podem ser convertidos em uma string.
Emile Bergeron
2

Uma linha única usando o oroperador:

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

você pode consultar este URL : para função

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

Então a saída deve ser,

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

Outra idéia para excluir o valor de uma matriz, use array_diff. Se eu quero

$my_array = array(1=>"a", "second_value"=>"b", 3=>"c", "d");
$new_array_without_value_c = array_diff($my_array, array("c"));

(Doc: http://php.net/manual/fr/function.array-diff.php )

Dana
fonte
3
Como isso é diferente da resposta ?
random_user_name 20/09/16
1

Eu acho que a maneira mais simples seria usar uma função com um loop 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);

A saída 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
fonte
1

Com o PHP 7.4 usando funções de seta:

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

Para manter uma matriz não associativa, envolva-a com array_values():

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