PHP массив удалить по значению (не ключу)


886

У меня есть массив PHP следующим образом:

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

Я хочу удалить элемент, содержащий значение $del_val(например, $del_val=401), но я не знаю его ключ. Это может помочь: каждое значение может быть там только один раз .

Я ищу простейшую функцию для выполнения этой задачи, пожалуйста.


1
@Adam Strudwick Но если у вас есть много удалений в этом массиве, было бы лучше, чтобы повторить его один раз и сделать его ключ таким же, как значение?
Дзона


Возможный дубликат PHP Удалить элемент из массива
Alex

Ответы:


1566

Используя array_search()и unset, попробуйте следующее:

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

array_search()возвращает ключ найденного элемента, который можно использовать для удаления этого элемента из исходного массива с помощью unset(). Он вернется FALSEпри неудаче, однако при успехе может вернуть значение false-y (ваш ключ может быть, 0например), поэтому используется !==оператор строгого сравнения .

Оператор if()проверит, array_search()вернулось ли значение, и выполнит действие, только если он это сделал.


14
Будет ли работать $ messages = array_diff ($ messages, array ($ del_val))? Будет ли лучше по производительности?
Адам Струдвик

9
@ Adam Почему бы не проверить это? У меня такое ощущение , что array_diff()будет медленнее , поскольку это сравнение двух массивов, а не просто поиск по одному , как array_search().
Bojangles

22
Даже если это действительно так, вам следует избегать присвоения значений в таких выражениях. Это только доставит вам неприятности.
Adlawson

17
Что если $keyесть 0?
Эван

16
Если 0искомое значение имеет ключ или любое другое значение Falsey, оно не будет сбрасывать значение и ваш код не будет работать. Вы должны проверить $key === false. (отредактировал - ты понял)
Эван

674

Что ж, удаление элемента из массива в основном просто устанавливает разницу с одним элементом.

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

Это хорошо обобщает, вы можете удалить столько элементов, сколько хотите одновременно, если хотите.

Отказ от ответственности: обратите внимание, что мое решение создает новую копию массива, сохраняя при этом старый нетронутым в отличие от принятого ответа, который изменяется. Выберите тот, который вам нужен.


32
это работает только для объектов, которые могут быть преобразованы в строку
nischayn22

7
Кажется, я получаю «Ошибка разбора» за то [$element], что я использовал array($element)вместо этого. Не важно, но просто хотел, чтобы любой, у кого была похожая проблема, знал, что они не одни
Ангад

8
Конечно, я предположил, что PHP 5.4 сейчас в большинстве своем отбрасывает старую нотацию. Спасибо за замечание.
Рок Краль

22
Стоит отметить, что по какой-то причине array_diffиспользуется (string) $elem1 === (string) $elem2как условие равенства, $elem1 === $elem2а не так, как вы могли бы ожидать. Проблема, на которую указывает @ nischayn22, является следствием этого. Если вы хотите, чтобы что-то использовалось в качестве служебной функции, которая будет работать для массивов произвольных элементов (которые могут быть объектами), ответ Bojangle может быть лучше по этой причине.
Марк Эмери

4
Также обратите внимание, что этот метод выполняет внутреннюю сортировку для каждого аргумента array_diff()и, таким образом, подталкивает время выполнения до O (n lg n) из O (n).
Яцк

115

Один интересный способ заключается в использовании array_keys():

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

array_keys()Функция принимает два дополнительных параметра , чтобы возвращать только ключи для конкретного значения и требуется ли проверка строгая (т.е. с использованием === для сравнения).

Это также может удалить несколько элементов массива с одинаковым значением (например [1, 2, 3, 3, 4]).


3
@ blasteralfredΨ Линейный поиск - O (n); Я не уверен, почему вы, кажется, думаете, что это проблема.
Ja͢ck

1
Да, это эффективно для выбора нескольких элементов / ключей массива.
Оки Эри Ринальди

3
Это лучше всего подходит для массивов, которые могут содержать не все уникальные значения.
Derokorian

Проблема в том, что он оставляет индекс ключей в отсортированном виде: [0] - a, [2] - b ([1] пропало, но массив все еще его пропускает)
Rodniko

3
@Rodniko, в этом случае вам также понадобится array_values(); оставшиеся ключи все еще находятся в том же порядке, так что технически это не «несортировано»
Ja͢ck

55

Если вы точно знаете, что ваш массив будет содержать только один элемент с этим значением, вы можете сделать

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

Однако, если ваше значение может встречаться в массиве более одного раза, вы можете сделать это

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

Примечание: Второй вариант работает только для PHP5.3 + с Closures


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

11
Это работает только тогда, когда ваш массив не содержит повторяющихся значений, кроме тех, которые вы пытаетесь удалить.
jberculo

2
@jberculo и иногда это именно то, что вам нужно, в некоторых случаях это спасает меня от создания уникального массива на нем aswel
DarkMukke

Возможно, но я бы использовал функции, специально предназначенные для этого, вместо того, чтобы быть просто счастливым побочным эффектом функции, которая в основном используется и предназначена для чего-то другого. Это также сделает ваш код менее прозрачным.
Jberculo

В сообщении говорится, что «каждое значение может быть только один раз», это должно работать. Было бы неплохо, если бы автор использовал имена переменных smae и добавил небольшое
пояснение

2
по-видимому, это самый быстрый по сравнению с выбранным решением, я сделал небольшой тест.
AMB

28

Посмотрите на следующий код:

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

Ты можешь сделать:

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

И это даст вам этот массив:

array('nice_item', 'another_liked_item')

1
Для ассоциативных массивов вы должны использовать array_diff_assoc ()
theCodeMachine

5
Чем это отличается от этого ответа ?
random_user_name

26

Лучший способ это array_splice

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

Причина для Лучшего находится здесь в http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/


4
Это не будет работать с ассоциативными массивами и массивами с пробелами в ключах, например [1, 2, 4 => 3].
Ja͢ck

Нет, извините, это сработает. Пожалуйста, прочитайте статью, которую я предоставил ссылку
Эйри

4
Не будет Рассмотрим массив моего комментария выше; после того, как я использую ваш код для удаления значения 3, массив будет [1, 2, 3]; другими словами, значение не было удалено. Чтобы быть ясным, я не говорю, что это терпит неудачу во всех сценариях, только этот.
Яцк

1
array_splice - лучший метод, unset не будет корректировать индексы массива после удаления
Raaghu

21

Или просто ручным способом:

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

Это самый безопасный из них, потому что у вас есть полный контроль над вашим массивом


1
Использование array_splice()вместо unset()будет также переупорядочивать индексы массива, что может быть лучше в этом случае.
Даниэле Орландо

20

С помощью следующего кода повторяющиеся значения будут удалены из сообщений $.

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


3
Up-голосование. Это был уже среди других ответов, но вы говорите это лучше, оставляя это простым, как у вас. Ответ просто "array_diff"
ghbarratt

1
Выглядит просто, но это меняет сложность с O (n) на O (n lg n). Так что на самом деле все сложнее;)
Кшиштоф Пшигода

20

Если у вас есть PHP 5.3+, есть однострочный код:

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

Ты уверен? Это закрытие не имеет доступа $value, поэтому на самом деле его нужно поместить в мини-класс, чтобы вы могли получить доступ $valueк закрытию ....
random_user_name

@cale_b, я обновил пример. Также вот ссылка: php.net/manual/en/functions.anonymous.php
Дэвид Лин

3
Вы могли бы также написать всю свою кодовую базу в одну строку, если вы называете это «однострочный код»
Милан Симек

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

Вывод

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


2
Я не уверен, что это быстрее, так как это решение включает в себя несколько вызовов функций.
Джулиан Паоло Даяг

13

ты можешь сделать:

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

Объяснение : Удалить элемент, имеющий ключ, 401после переворачивания массива.


Вы должны быть очень осторожны, если хотите сохранить государство. потому что весь будущий код должен иметь значения вместо ключей.
saadlulu

1
Массив @saadlulu $ messages не будет перевернут, так как array_flip () не влияет на исходный массив, поэтому результирующий массив после применения предыдущей строки будет таким же, за исключением того, что нежелательный результат будет удален.
Кураши

2
не уверен, что это правильно, что если есть несколько элементов со значением 401?
Zippp

Это все равно сохранит ключи.
Сабольч Палл

8

Чтобы удалить несколько значений, попробуйте следующее:

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

6

Заимствовал логику underscore.JS _.reject и создал две функции (люди предпочитают функции !!)

array_reject_value: эта функция просто отклоняет указанное значение (также работает для PHP 4,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: эта функция просто отклоняет вызываемый метод (работает для 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;
}

Таким образом, в нашем текущем примере мы можем использовать вышеуказанные функции следующим образом:

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

или даже лучше: (поскольку это дает нам лучший синтаксис для использования, как у array_filter )

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

Выше можно использовать для более сложных вещей, например, скажем, мы хотели бы удалить все значения, которые больше или равны 401, мы могли бы просто сделать это:

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

1
Разве это не изобретательский фильтр? php.net/manual/en/function.array-filter.php
Ричард Дуэрр

Да, в самом деле. Как я уже говорил в посте "или даже лучше: (так как это дает нам лучший синтаксис для использования, как у array_filter)". Иногда вам действительно нужно, чтобы функция отклоняла как подчеркивание, и это на самом деле просто противоположность фильтра (и вам нужно получить ее с как можно меньшим количеством кода). Это то, что делают функции. Это простой способ отклонить значения.
Джон Скумбурдис

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

Попробуйте это, это лучший и самый быстрый способ удалить элемент по значению


5

Ответ @ Bojangles помог мне. Спасибо.

В моем случае массив может быть ассоциативным или нет, поэтому я добавил следующую функцию

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
 }

}

С уважением



4

Принятый ответ преобразует массив в ассоциативный массив, поэтому, если вы хотите сохранить его в качестве неассоциативного массива с принятым ответом, вам, возможно, придется его использовать array_values.

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

Ссылка здесь


4

Согласно вашему требованию « каждое значение может быть там только один раз », если вы просто заинтересованы в сохранении уникальных значений в вашем массиве, то это array_unique()может быть то, что вы ищете.

Входные данные:

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

Результат:

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

4

Если значения, которые вы хотите удалить, находятся или могут быть в массиве. Используйте функцию array_diff . Кажется, отлично работает для таких вещей.

array_diff

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

1
Чем это отличается от этого ответа ?
random_user_name

4

Я знаю, что это совсем не эффективно, но просто, интуитивно понятно и легко читается.
Так что, если кто-то ищет не очень интересное решение, которое можно расширить для работы с большим количеством значений или с более конкретными условиями ... вот простой код:

$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


3

Если вы не знаете его ключ, значит, он не имеет значения.

Вы можете поместить значение в качестве ключа, это означает, что оно мгновенно найдет значение. Лучше, чем использовать поиск по всем элементам снова и снова.

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

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

Работает только для объектов, которые могут быть преобразованы в строку.
Эмиль Бержерон,

2

Однострочник с использованием orоператора:

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

2

Вы можете сослаться на этот URL : для функции

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

Тогда вывод должен быть,

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


1

Я думаю, что самым простым способом было бы использовать функцию с циклом 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);

Выход будет:

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

В PHP 7.4 с использованием функций стрелок:

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

Чтобы сохранить его в неассоциативном массиве, оберните его array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.