Xóa mảng PHP theo giá trị (không phải khóa)


886

Tôi có một mảng PHP như sau:

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

Tôi muốn xóa phần tử chứa giá trị $del_val(ví dụ $del_val=401:), nhưng tôi không biết khóa của nó. Điều này có thể giúp: mỗi giá trị chỉ có thể ở đó một lần .

Tôi đang tìm kiếm chức năng đơn giản nhất để thực hiện nhiệm vụ này, xin vui lòng.


1
@Adam Strudwick Nhưng nếu bạn có nhiều thao tác xóa trên mảng này, sẽ tốt hơn nếu lặp lại nó một lần và làm cho khóa của nó giống như giá trị?
dzona


Câu trả lời:


1566

Sử dụng array_search()unsetthử các cách sau:

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

array_search()trả về khóa của phần tử mà nó tìm thấy, có thể được sử dụng để loại bỏ phần tử đó khỏi mảng ban đầu bằng cách sử dụng unset(). Nó sẽ trả FALSEvề khi thất bại, tuy nhiên nó có thể trả về giá trị false-y khi thành công ( 0ví dụ khóa của bạn ), đó là lý do tại sao !==toán tử so sánh nghiêm ngặt được sử dụng.

Câu if()lệnh sẽ kiểm tra xem có array_search()trả về một giá trị hay không và sẽ chỉ thực hiện một hành động nếu nó đã làm.


14
$ Messages = Array_diff ($ message, mảng ($ del_val)) cũng hoạt động chứ? Nó sẽ tốt hơn trong hiệu suất?
Adam Strudwick

9
@Adam Tại sao không kiểm tra nó? Cảm giác của tôi là array_diff()sẽ chậm hơn khi so sánh hai mảng, không chỉ đơn giản là tìm kiếm thông qua một lượt thích array_search().
Bojangles

22
Mặc dù điều này là hợp lệ, bạn nên tránh gán giá trị trong các câu lệnh như thế. Nó sẽ chỉ khiến bạn gặp rắc rối.
adlawson

17
Nếu $key0gì?
evan

16
Nếu giá trị bạn đang tìm kiếm có khóa 0hoặc bất kỳ giá trị falsey nào khác, thì nó sẽ không đặt giá trị và mã của bạn sẽ không hoạt động. Bạn nên kiểm tra $key === false. (chỉnh sửa- bạn hiểu rồi)
evan

674

Chà, xóa một phần tử khỏi mảng về cơ bản chỉ là đặt sự khác biệt với một phần tử.

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

Nó khái quát độc đáo, bạn có thể loại bỏ bao nhiêu yếu tố tùy thích cùng một lúc, nếu bạn muốn.

Tuyên bố miễn trừ trách nhiệm: Lưu ý rằng giải pháp của tôi tạo ra một bản sao mới của mảng trong khi vẫn giữ nguyên cái cũ trái ngược với câu trả lời được chấp nhận sẽ đột biến. Chọn một trong những bạn cần.


32
điều này chỉ hoạt động cho các đối tượng có thể được chuyển đổi thành một chuỗi
nischayn22

7
Tôi dường như nhận được một 'Lỗi phân tích cú pháp' để nói rằng [$element], tôi đã sử dụng array($element)thay thế. Không có vấn đề gì, nhưng chỉ muốn bất cứ ai gặp vấn đề tương tự đều biết rằng họ không cô đơn
Angad

8
Chắc chắn, tôi đã giả sử PHP 5.4 hiện đang chiếm đa số để bỏ ký hiệu cũ. Cảm ơn đã nhận xét.
Rok Kralj

22
Điều đáng chú ý là vì một số lý do array_diffsử dụng (string) $elem1 === (string) $elem2làm điều kiện bình đẳng của nó, không $elem1 === $elem2như bạn mong đợi. Vấn đề được chỉ ra bởi @ nischayn22 là hậu quả của việc này. Nếu bạn muốn một cái gì đó sử dụng như một hàm tiện ích sẽ hoạt động cho các mảng của các phần tử tùy ý (có thể là các đối tượng), câu trả lời của Bojangle có thể tốt hơn vì lý do này.
Đánh dấu Amery

4
Cũng lưu ý rằng phương thức này thực hiện sắp xếp nội bộ cho từng đối số array_diff()và do đó làm giảm thời gian chạy lên đến O (n lg n) từ O (n).
Ja͢ck

115

Một cách thú vị là sử dụng array_keys():

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

Các array_keys()chức năng phải mất hai tham số bổ sung để trở lại chỉ chìa khóa cho một giá trị đặc biệt và liệu kiểm tra nghiêm ngặt là cần thiết (tức là sử dụng === để đối chiếu).

Điều này cũng có thể loại bỏ nhiều mục mảng có cùng giá trị (ví dụ [1, 2, 3, 3, 4]).


3
@ blasteralfredΨ Một tìm kiếm tuyến tính là O (n); Tôi không chắc tại sao bạn nghĩ rằng đó là một vấn đề.
Ja͢ck

1
Có, điều này có hiệu quả để chọn nhiều mục / khóa mảng.
Oki Erie Rinaldi

3
Điều này là tốt nhất cho các mảng có thể không chứa tất cả các giá trị duy nhất.
Derokorian

Vấn đề là nó khiến chỉ số của các khóa bị khóa: [0] - a, [2] - b ([1] đã biến mất nhưng mảng vẫn nhớ nó)
Rodniko

3
@Rodniko trong trường hợp bạn cũng sẽ cần array_values(); các phím còn lại vẫn theo cùng một thứ tự, vì vậy về mặt kỹ thuật, nó không phải là "chưa được sắp xếp"
Ja͢ck

55

Nếu bạn biết chắc chắn rằng mảng của bạn sẽ chỉ chứa một phần tử có giá trị đó, bạn có thể làm

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

Tuy nhiên, nếu giá trị của bạn có thể xảy ra nhiều lần trong mảng của bạn, bạn có thể làm điều này

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

Lưu ý: Tùy chọn thứ hai chỉ hoạt động cho PHP5.3 + với Đóng


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

11
Điều này chỉ hoạt động khi mảng của bạn không chứa các giá trị trùng lặp khác với các giá trị bạn đang cố xóa.
jberculo

2
@jberculo và đôi khi chính xác là những gì bạn cần, trong một số trường hợp, nó giúp tôi tiết kiệm được một mảng duy nhất trên nó
DarkMukke 14/11/14

Có thể, nhưng tôi sẽ sử dụng các chức năng được thiết kế đặc biệt để làm điều đó, thay vì chỉ là một tác dụng phụ may mắn của một chức năng về cơ bản được sử dụng và dành cho mục đích khác. Nó cũng sẽ làm cho mã của bạn không minh bạch.
jberculo

Thông báo cho biết "mỗi giá trị chỉ có thể ở đó một lần" sẽ hoạt động. Sẽ thật tuyệt nếu người đăng đã sử dụng tên biến
smae

2
Rõ ràng đây là cách nhanh nhất so với giải pháp được chọn, tôi đã làm điểm chuẩn nhỏ.
AMB

28

Hãy xem mã sau đây:

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

Bạn có thể làm:

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

Và điều đó sẽ giúp bạn có được mảng này:

array('nice_item', 'another_liked_item')

1
Đối với các mảng kết hợp, bạn phải sử dụng mảng_diff_assoc ()
theCodeMachine

5
Làm thế nào là khác bất kỳ câu trả lời này ?
Random_user_name

26

Cách tốt nhất là array_splice

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

Lý do tốt nhất có tại đây tại http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/


4
Điều này sẽ không hoạt động trên các mảng kết hợp và mảng có khoảng trống trong khóa của họ, ví dụ [1, 2, 4 => 3].
Ja͢ck

Không xin lỗi điều này sẽ làm việc. Vui lòng đọc bài viết tôi đã cung cấp liên kết
Airy

4
Nó sẽ không. Hãy xem xét các mảng nhận xét trên của tôi; sau khi tôi sử dụng mã của bạn để loại bỏ giá trị 3, mảng sẽ là [1, 2, 3]; nói cách khác, giá trị không bị xóa. Để rõ ràng, tôi không nói rằng nó thất bại trong tất cả các kịch bản, chỉ có điều này.
Ja͢ck

1
mảng_splice là phương pháp tốt nhất, bỏ đặt sẽ không điều chỉnh các chỉ mục mảng sau khi xóa
Raaghu

21

Hoặc đơn giản, cách thủ công:

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

Đây là cách an toàn nhất trong số họ vì bạn có toàn quyền kiểm soát mảng của mình


1
Sử dụng array_splice()thay vì unset()sẽ sắp xếp lại các chỉ mục mảng, điều này có thể tốt hơn trong trường hợp này.
Daniele Orlando

20

Theo đoạn mã sau, các giá trị lặp lại sẽ bị xóa khỏi các thông báo $.

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


3
Bình chọn lên. Nó đã là một trong những câu trả lời khác nhưng bạn nói nó tốt nhất bằng cách giữ cho nó đơn giản, như bạn có. Câu trả lời đơn giản là "array_diff"
ghbarratt

1
Trông đơn giản nhưng nó thay đổi độ phức tạp từ O (n) sang O (n lg n). Vì vậy, thực tế nó phức tạp hơn;)
Krzysztof Przygoda

20

Nếu bạn có PHP 5.3+, có một mã dòng:

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

Bạn có chắc không? Việc đóng đó không có quyền truy cập $value, vì vậy thực sự nó phải được đưa vào một lớp nhỏ để bạn có thể truy cập $valuetrong bao đóng ....
Random_user_name

@cale_b, tôi đã cập nhật ví dụ. Ngoài ra, đây là tài liệu tham khảo: php.net/manual/en/fiances.anonymous.php
David Lin

3
Bạn cũng có thể viết toàn bộ cơ sở mã của mình trên một dòng nếu bạn gọi đây là "mã một dòng"
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);

Đầu ra

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


2
Tôi không chắc liệu điều này có nhanh hơn không vì giải pháp này liên quan đến nhiều cuộc gọi chức năng.
Julian Paolo Dayag

13

bạn có thể làm:

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

Giải thích : Xóa phần tử có khóa 401sau khi lật mảng.


Bạn phải rất cẩn thận nếu bạn muốn giữ gìn trạng thái. bởi vì tất cả các mã trong tương lai sẽ phải có các giá trị thay vì các khóa.
saadlulu

1
@saadlulu $ mảng tin nhắn sẽ không được lật vì mảng_flip () không ảnh hưởng đến mảng ban đầu, do đó mảng kết quả sau khi áp dụng dòng trước sẽ giống nhau ngoại trừ kết quả không mong muốn sẽ bị xóa.
Qurashi

2
không chắc chắn nếu điều này là chính xác, nếu có một số phần tử có giá trị là 401gì?
Zippp

Điều này vẫn sẽ bảo tồn các khóa.
Szabolcs Páll

8

Để xóa nhiều giá trị, hãy thử cái này:

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

6

Mượn logic của gạch dưới.JS _.reject và tạo hai hàm (mọi người thích các hàm !!)

mảng numject_value: Hàm này chỉ đơn giản là từ chối giá trị được chỉ định (cũng hoạt động với PHP4,5,7)

function array_reject_value(array &$arrayToFilter, $deleteValue) {
    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if ($value !== $deleteValue) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

mảng numject: Hàm này chỉ đơn giản là từ chối phương thức có thể gọi được (hoạt động với 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;
}

Vì vậy, trong ví dụ hiện tại của chúng tôi, chúng tôi có thể sử dụng các chức năng trên như sau:

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

hoặc thậm chí tốt hơn: (vì điều này cung cấp cho chúng tôi một cú pháp tốt hơn để sử dụng như mảng_filter )

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

Ở trên có thể được sử dụng cho những thứ phức tạp hơn như giả sử chúng tôi muốn xóa tất cả các giá trị lớn hơn hoặc bằng 401, chúng tôi chỉ có thể làm điều này:

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

1
Đây không phải là bộ lọc phát minh lại? php.net/manual/en/feft.array-filter.php
Richard Duerr

Vâng thực sự. Như tôi đã nói tại bài viết "hoặc thậm chí tốt hơn: (vì điều này cung cấp cho chúng tôi một cú pháp tốt hơn để sử dụng như mảng_filter)". Đôi khi bạn thực sự chỉ cần có chức năng từ chối dưới dạng gạch dưới và nó thực sự chỉ ngược lại với bộ lọc (và bạn cần lấy nó với càng ít mã càng tốt). Đây là những gì các chức năng đang làm. Đây là một cách đơn giản để từ chối các giá trị.
John Skoumbourdis

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

Hãy thử điều này, Đây là cách tốt nhất và nhanh nhất để loại bỏ yếu tố theo giá trị


5

@Bojangles trả lời đã giúp tôi. Cảm ơn bạn.

Trong trường hợp của tôi, mảng có thể kết hợp hoặc không, vì vậy tôi đã thêm chức năng sau

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
 }

}

Trân trọng



4

Câu trả lời được chấp nhận chuyển đổi mảng thành mảng kết hợp, vì vậy, nếu bạn muốn giữ nó là một mảng không liên kết với câu trả lời được chấp nhận, bạn cũng có thể phải sử dụng array_values.

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

Tài liệu tham khảo ở đây


4

Theo yêu cầu của bạn " mỗi giá trị chỉ có thể ở đó một lần " nếu bạn chỉ muốn giữ các giá trị duy nhất trong mảng của mình, thì đó array_unique()có thể là những gì bạn đang tìm kiếm.

Đầu vào:

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

Kết quả:

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


4

Tôi biết điều này không hiệu quả chút nào nhưng đơn giản, trực quan và dễ đọc.
Vì vậy, nếu ai đó đang tìm kiếm một giải pháp không mấy ưa thích có thể được mở rộng để hoạt động với nhiều giá trị hơn hoặc điều kiện cụ thể hơn .. thì đây là một mã đơn giản:

$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

Lấy khóa mảng với array_search().


2
Làm cách nào để xóa giá trị IF và chỉ khi tôi tìm thấy nó với mảng_search?
Adam Strudwick

3
$ k = mảng_search ($ kim, $ haystack, true); if ($ k! == false) {unset ($ haystack [$ k]); }
evan

3

Nếu bạn không biết khóa của nó, điều đó có nghĩa là nó không thành vấn đề.

Bạn có thể đặt giá trị làm khóa, điều đó có nghĩa là nó sẽ ngay lập tức tìm thấy giá trị. Tốt hơn là sử dụng tìm kiếm trong tất cả các yếu tố nhiều lần.

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

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

Chỉ hoạt động cho các đối tượng có thể được chuyển đổi thành một chuỗi.
Emile Bergeron

2

Một lớp lót sử dụng ortoán tử:

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

2

bạn có thể tham khảo URL này : cho chức năng

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

Sau đó, đầu ra nên,

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


1

Tôi nghĩ cách đơn giản nhất là sử dụng hàm với vòng lặp 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);

Đầu ra sẽ là:

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

Với PHP 7.4 sử dụng các hàm mũi tên:

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

Để giữ cho nó một mảng không liên kết, hãy bọc nó bằng array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.