Видалення елемента масиву за значенням


166

Мені потрібно видалити елемент масиву із заданим значенням:

if (in_array($id, $items)) {
    $items = array_flip($items);
    unset($items[ $id ]);
    $items = array_flip($items);
}

Чи можна це зробити більш коротким (більш ефективним) способом?


Відповіді:


423

Це можна виконати за допомогою простого однолінійного.

Маючи цей масив:

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

Ви можете зробити:

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

А значення $arrбуде:

array('nice_item', 'another_liked_item')

Сподіваюся, це допомагає написати гарний код.


2
Ні, це робить роботу з посилальними масивами, то array_diffфункція є неруйнуючої, він повертає новий масив.
Алехандро Гарсія Іглесіас

2
@srcspider чому б і ні? $referenced = array_diff($referenced, $items_to_remove);
Алехандро Гарсія Іглесіас

1
$ referenced тепер вказує на новий масив, масив, який ви хотіли змінити, все ще має старі значення.
srcspider

2
@srcspider добре, ти скажи мені, що тоді тут відбувається ... codepad.org/11ZhiFP0
Алехандро Гарсія Іглесіас

1
моє ліжко; Перемінний псевдонім "Псевдонім" завжди
переміщує

37

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

$arr = array(0 => 123456);
for($i = 1; $i < 500000; $i++) {
    $arr[$i] = rand(0,PHP_INT_MAX);
}

shuffle($arr);
$arr2 = $arr;
$arr3 = $arr;

/** 
 * Method 1 - array_search()
 */
$start = microtime(true);
while(($key = array_search(123456,$arr)) !== false) {
    unset($arr[$key]);
}
echo count($arr). ' left, in '.(microtime(true) - $start).' seconds<BR>';

/** 
 * Method 2 - basic loop
 */
$start = microtime(true);
foreach($arr2 as $k => $v) {
    if ($v == 123456) {
        unset($arr2[$k]);
    }
}
echo count($arr2). 'left, in '.(microtime(true) - $start).' seconds<BR>';

/** 
 * Method 3 - array_keys() with search parameter
 */
$start = microtime(true);
$keys = array_keys($arr3,123456);
foreach($keys as $k) {
    unset($arr3[$k]);
}
echo count($arr3). 'left, in '.(microtime(true) - $start).' seconds<BR>';

Третій метод array_keys()із вказаним необов'язковим параметром пошуку здається найкращим методом. Приклад виводу:

499999 left, in 0.090957164764404 seconds
499999left, in 0.43156313896179 seconds
499999left, in 0.028877019882202 seconds

Судячи з цього, рішення, яке я б тоді застосував, було б:

$keysToRemove = array_keys($items,$id);
foreach($keysToRemove as $k) {
    unset($items[$k]);
}

Я думаю, що array_search набагато читає код, ніж використання методу array_diff. Upvote
kendepelchin

@zombat Цікаво, чи замовлення має щось спільне з результатами. Можливо, що перетасовка додає значення, яке ми шукаємо, чи ближче до передньої, так і до кінця. Крім цього ... +1
Генерал Реднек

31

Як щодо:

if (($key = array_search($id, $items)) !== false) unset($items[$key]);

або для кількох значень:

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

Це також запобіжить втраті ключів, що є побічним ефектом array_flip().


1
не працюватиме, якщо $ id є першим елементом масиву, краще таким чином: if (($ key = array_search ($ id, $ items))! == false) unset ($ items [$ key]);
Марек


8

Найпотужнішим рішенням буде використання array_filter, яке дозволяє визначити власну функцію фільтрації.

Але дехто може сказати, що у вашій ситуації це трохи надмірно ...
Простієї foreachпетлі, щоб пройти масив та вийняти потрібний вам елемент, повинно бути достатньо.

Щось подібне, у вашому випадку, ймовірно, повинно зробити трюк:

foreach ($items as $key => $value) {
    if ($value == $id) {
        unset($items[$key]);
        // If you know you only have one line to remove, you can decomment the next line, to stop looping
        //break;
    }
}

6

Спробуйте array_search ()


3
Я просто прочитав документацію, і рекомендую використовувати array_keys (), щоб знайти всі ключі, пов'язані зі значенням.
Савагеман

@Savageman - Погодився. Я запустив швидкий показник і, array_keys()здається, виконує краще, ніж array_search()для цього завдання.
zombat

6

Ваші рішення працюють лише за наявності у вас масивів унікальних значень

Побачити:

<?php
$trans = array("a" => 1, "b" => 1, "c" => 2);
$trans = array_flip($trans);
print_r($trans);
?>

Кращим способом було б невстановлено array_search в циклі, якщо це необхідно.


Ви маєте рацію, але в цьому конкретному випадку я майже впевнений, що цінності унікальні :)
Марек

5

без перекидання:

<?php
foreach ($items as $key => $value) {
    if ($id === $value) {
        unset($items[$key]);
    }
}


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.