Видалити масив PHP за значенням (не ключовим)


885

У мене є масив PHP наступним чином:

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

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

Я шукаю найпростішу функцію для виконання цього завдання, будь ласка.


1
@Adam Strudwick Але якщо у вас є багато видалень з цього масиву, було б краще повторити його один раз і зробити його ключ таким же, як значення?
дзона

Те саме питання: stackoverflow.com/questions/1883421/…
Eric Lavoie

Відповіді:


1565

Використовуйте array_search()та unsetспробуйте наступне:

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

array_search()повертає ключ знайденого елемента, який може бути використаний для видалення цього елемента з початкового масиву за допомогою unset(). Він повернеться 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або будь-яке інше значення фальси, воно не скине значення, і ваш код не працюватиме. Вам слід випробувати $key === false. (редагувати - ви це отримали)
evan

671

Що ж, видалення елемента з масиву - це в основному лише встановлена різниця з одним елементом.

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

Це добре узагальнюється, ви можете одночасно видалити скільки завгодно елементів, якщо хочете.

Відмова: Зауважте, що моє рішення створює нову копію масиву, зберігаючи старий недоторканим на відміну від прийнятої відповіді, яка мутує. Виберіть потрібну.


32
це працює лише для об’єктів, які можна перетворити на рядок
nischayn22

7
Мені здається, я отримую "помилку синтаксичного аналізу", кажучи [$element], array($element)замість цього я використовував . Немає великого, але просто хотів, щоб кожен, хто мав подібну проблему, знав, що вони не самотні
Angad

8
Звичайно, я припустив, що PHP 5.4 зараз є більшістю, щоб відмовитися від старої нотації. Дякуємо за зауваження.
Rok Kralj

22
Варто зазначити, що з певних причин array_diffвикористовується (string) $elem1 === (string) $elem2як умова рівності, а не $elem1 === $elem2як ви могли очікувати. Питання, на яке вказував @ nischayn22, є наслідком цього. Якщо ви хочете щось використовувати як функцію утиліти, яка буде працювати для масивів довільних елементів (які можуть бути об'єктами), відповідь Боянгла може бути кращою з цієї причини.
Марк Амері

4
Також зауважте, що цей метод виконує своєрідне внутрішнє сортування для кожного аргументу array_diff()та, таким чином, відсуває час виконання до O (n lg n) від O (n).
Ja͢ck

115

Один цікавий спосіб - це використання array_keys():

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

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

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


3
@ blasteralfredΨ Лінійний пошук - O (n); Я не впевнений, чому ви, здається, думаєте, що це проблема.
Ja͢ck

1
Так, це ефективно для вибору декількох елементів / ключів масиву.
Окі Ері Рінальді,

3
Це найкраще для масивів, які можуть не містити всіх унікальних значень.
Дерокоріан

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

3
@ Роднико в такому випадку вам також знадобиться 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 + із закриттями


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

Вибачте, це не спрацює. Будь ласка, прочитайте статтю, яку я надав за посиланням
Airy

4
Це не стане. Розгляньте масив мого вище коментаря; після того як я використаю ваш код для видалення значення 3, масив буде [1, 2, 3]; Іншими словами, значення не було видалено. Щоб було зрозуміло, я не кажу, що це не вдається в усіх сценаріях, тільки в цьому.
Ja͢ck

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
Вгору проголосували. Це було вже серед інших відповідей, але ви це краще за все говорите, просто, як у вас є. Відповідь просто "array_diff"
ghbarratt

1
Виглядає просто, але це змінює складність з O (n) на O (n lg n). Отже, насправді це складніше;)
Krzysztof Przygoda

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

Це збереже ключі.
Szabolcs Páll


6

Позичив логіку підкреслення.JS _.reject і створив дві функції (люди віддають перевагу функції !!)

array_reject_value: Ця функція просто відхиляє вказане значення (також працює для 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: Ця функція просто відхиляє метод виклику (працює для 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 one)". Іноді вам просто потрібно, щоб функція відхилялася як підкреслення, і це насправді навпаки фільтра (і вам потрібно отримати його з якомога меншим кодом). Це те, що виконують функції. Це простий спосіб відхилення значень.
Джон Скумбурдіс

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_diff () ), використовуйте наступне:

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

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

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

$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

Отримайте ключ масиву за допомогою array_search().


2
Як видалити значення IF і лише якщо я знайду його з array_search?
Адам Струдвік

3
$ k = array_search ($ голка, $ копиця сіна, правда); if ($ k! == false) {unset ($ копиця сіна [$ k]); }
еван

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.