Cách xóa các giá trị trùng lặp khỏi mảng đa chiều trong PHP


306

Làm cách nào tôi có thể xóa các giá trị trùng lặp khỏi một mảng đa chiều trong PHP?

Mảng ví dụ:

Array
(
    [0] => Array
    (
        [0] => abc
        [1] => def
    )

    [1] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [2] => Array
    (
        [0] => mno
        [1] => pql
    )

    [3] => Array
    (
        [0] => abc
        [1] => def
    )

    [4] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [5] => Array
    (
        [0] => mno
        [1] => pql
    )

)

Câu trả lời:


637

Đây là một cách khác. Không có biến trung gian được lưu.

Chúng tôi đã sử dụng điều này để sao chép kết quả từ nhiều truy vấn chồng chéo.

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

23
Do không xác định nên điều này càng chậm và càng chậm thì mảng càng lớn và phức tạp. Có một lý do tôi đã sử dụng Array_intersect_key (nửa năm trước câu trả lời này).
OIS

11
@OIS cũng vừa kiểm tra nó, đã có một lỗi đánh máy nhưng nó hoạt động .. cảm ơn anh bạn!: $ No_d repeatates = Array_intersect_key ($ mảng, Array_unique (mảng_map ('serialize', $ mảng));
trevorkavanaugh

3
nếu bạn muốn chỉ mục liên tục, hãy sử dụng Array_values ​​tức là $ input = Array_values ​​(Array_map ("unserialize", Array_unique (Array_map ("serialize", $ input))));
lbsweek

4
Ngày nay, bạn có thể sẽ chọn json_encode và json_decode thay vì tuần tự hóa PHP. nên có lợi ích cho các giá trị được cung cấp bạn không chạy vào các chi tiết tuần tự hóa PHP mà tuần tự hóa / hủy xác định các tàu với và rất có thể là không mong muốn.
hakre

2
Coi chừng đó serialize(array('a' => '1', 'b' => '1'))là khác nhau serialize(array('b' => '1', 'a' => '1')). Tùy chọn này sẽ thất bại cho các mảng được sử dụng như setshoặc (hash)maps.
Andras Gyomrey

240

Kể từ 5.2.9, bạn có thể sử dụng array_unique()nếu bạn sử dụng SORT_REGULARcờ như vậy:

array_unique($array, SORT_REGULAR);

Điều này làm cho hàm so sánh các phần tử cho đẳng thức như thể $a == $bđang được sử dụng, điều này là hoàn hảo cho trường hợp của bạn.

Đầu ra

Array
(
    [0] => Array
        (
            [0] => abc
            [1] => def
        )

    [1] => Array
        (
            [0] => ghi
            [1] => jkl
        )

    [2] => Array
        (
            [0] => mno
            [1] => pql
        )

)

Mặc dù vậy, hãy ghi nhớ rằng tài liệu nêu rõ:

array_unique() không có ý định làm việc trên các mảng đa chiều.


2
Tôi đoán đây là giải pháp nhanh chóng và rõ ràng hơn so với giải pháp được chấp nhận! Hãy bỏ phiếu cho cái này! :) Hmmm trên trang php chúng ta có thể thấy rằng nó không nhanh như vậy, như tôi nghĩ ...
Andron

4
Điều kỳ lạ là sử dụng cờ SORT_REGULAR không hoạt động đối với tôi, để loại bỏ các mảng trùng lặp.
Stefan

4
@Stefan Bạn nói đúng; nó dường như không cho kết quả chính xác, nhưng có lẽ đó là một lỗi vì nó hoạt động với PHP 7 = /
Ja͢ck

4
Điều này cũng có vẻ hoạt động trong trường hợp của tôi nhưng có ai khác bị làm phiền bởi ghi chú này trong tài liệu Array_unique () không? php.net/manual/en/ Kẻ
Arleigh Hix

2
@Jack Bạn nói đúng đây là một lỗi của PHP 5.6,23: eval.in/645675 nhưng đã được sửa chữa kể từ phiên bản 7.0.8: eval.in/645676
Zack Morris

63

Tôi đã có một vấn đề tương tự nhưng tôi tìm thấy một giải pháp làm việc 100% cho nó.

<?php
    function super_unique($array,$key)
    {
       $temp_array = [];
       foreach ($array as &$v) {
           if (!isset($temp_array[$v[$key]]))
           $temp_array[$v[$key]] =& $v;
       }
       $array = array_values($temp_array);
       return $array;

    }


$arr="";
$arr[0]['id']=0;
$arr[0]['titel']="ABC";
$arr[1]['id']=1;
$arr[1]['titel']="DEF";
$arr[2]['id']=2;
$arr[2]['titel']="ABC";
$arr[3]['id']=3;
$arr[3]['titel']="XYZ";

echo "<pre>";
print_r($arr);
echo "unique*********************<br/>";
print_r(super_unique($arr,'titel'));

?>

1
Điều này trả lời một câu hỏi khác nhau. Xem tại đây: stackoverflow.com/questions/4585208/
Lần

Chức năng tuyệt vời! và trong trường hợp bạn đang xử lý các đối tượng: if (! [et ($ mảng -> $ v -> $ key)) $ mảng [$ v -> $ key] = & $ v;
Playnox 17/03/2016

35

Cách khác. Sẽ bảo quản chìa khóa là tốt.

function array_unique_multidimensional($input)
{
    $serialized = array_map('serialize', $input);
    $unique = array_unique($serialized);
    return array_intersect_key($input, $unique);
}

Đối với mảng lớn, phương pháp này thường nhanh hơn ít nhất 50% so với câu trả lời được chấp nhận.
Lorien Brunei

21

Nhận xét của người dùng về tài liệu Array_unique () có nhiều giải pháp cho vấn đề này. Đây là một trong số chúng:

kenrbnsn tại rbnsn dot com
27-tháng 9 năm 2005 12:09

Một Array_Unique khác cho các mảng đa cấp. Tôi chỉ thử nghiệm điều này trên các mảng hai lần, nhưng có lẽ nó có thể được khái quát hóa để biết thêm hoặc được thực hiện để sử dụng đệ quy.

Hàm này sử dụng các hàm serialize, Array_unique và unserialize để thực hiện công việc.


function multi_unique($array) {
    foreach ($array as $k=>$na)
        $new[$k] = serialize($na);
    $uniq = array_unique($new);
    foreach($uniq as $k=>$ser)
        $new1[$k] = unserialize($ser);
    return ($new1);
}

Đây là từ http://ca3.php.net/manual/en/feft.array-unique.php#57202 .


18

Nếu "loại bỏ trùng lặp" có nghĩa là "loại bỏ trùng lặp, nhưng để lại ở đó", thì một giải pháp có thể là áp dụng array_unique(...)"cột định danh" trước và sau đó loại bỏ trong mảng ban đầu tất cả các khóa, đã bị xóa khỏi mảng cột :

$array = [
    [
        'id' => '123',
        'foo' => 'aaa',
        'bar' => 'bbb'
    ],
    [
        'id' => '123',
        'foo' => 'ccc',
        'bar' => 'ddd'
    ],
    [
        'id' => '567',
        'foo' => 'eee',
        'bar' => 'fff'
    ]
];

$ids = array_column($array, 'id');
$ids = array_unique($ids);
$array = array_filter($array, function ($key, $value) use ($ids) {
    return in_array($value, array_keys($ids));
}, ARRAY_FILTER_USE_BOTH);

Kết quả là:

Array
(
    [0] => Array
        (
            [id] => 123
            [foo] => aaa
            [bar] => bbb
        )

    [2] => Array
        (
            [id] => 567
            [foo] => eee
            [bar] => fff
        )

)

18
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => john
        )

    [1] => Array
        (
            [id] => 2
            [name] => smith
        )

    [2] => Array
        (
            [id] => 3
            [name] => john
        )

    [3] => Array
        (
            [id] => 4
            [name] => robert
        )

)

$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);

Điều này sẽ loại bỏ các tên trùng lặp từ mảng. duy nhất bởi khóa


Đảm bảo rằng $arraycác phím bắt đầu từ "0". Các khóa của nó có thể $arraybắt đầu ở một số khác nếu $arraylà kết quả của thao tác mảng trước. Sử dụng array_valuesđể đặt lại các phím trở về "0"
stevevance


4

Chỉ cần sử dụng tùy chọn SORT_REGULAR làm tham số thứ hai.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR chỉ hoạt động trong PHP 7 vì PHP 5 có lỗi (mặc dù @ r3wt đúng theo tài liệu), hãy xem nhận xét của tôi trong câu trả lời cho ví dụ có thể chạy được stackoverflow.com/questions/307674/ tựa
Zack Morris

Tại sao bạn lại thêm cái này? Nó giống như câu trả lời này, lớn hơn câu trả lời của bạn hơn một năm: stackoverflow.com/a/18373723/870729
Random_user_name

3

nếu bạn cần loại bỏ trùng lặp trên các khóa cụ thể, chẳng hạn như id mysqli, thì đây là một funciton đơn giản

function search_array_compact($data,$key){
    $compact = [];
    foreach($data as $row){
        if(!in_array($row[$key],$compact)){
            $compact[] = $row;
        }
    }
    return $compact;
}

Điểm thưởng Bạn có thể vượt qua một loạt các khóa và thêm một foreach bên ngoài, nhưng nó sẽ chậm hơn 2 lần cho mỗi khóa bổ sung.


3

Một cách rất dễ dàng và hợp lý để Duy nhất một mảng nhiều chiều như sau,

Nếu bạn có mảng như thế này:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value1
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value4
        )
)

sử dụng foreachđể giải quyết điều này:

foreach($array as $k=>$v){
    $unique=array_unique($v);
    $array[$k]=$unique;
}

nó sẽ cho bạn kết quả như sau:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
            [4] => Value4
        )
)

và nếu bạn muốn sắp xếp lại thứ tự các phím,

foreach($array as $k=>$v){
    $unique= array_values(array_unique($v));
    $array[$k]=$unique;
}

Thao tác này sẽ cung cấp cho bạn các giá trị chính được sắp xếp như thế này:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
            [3] => Value4
        )
)

Tôi hy vọng điều này sẽ xóa tất cả mọi thứ.


2

nếu bạn có một mảng như thế này:

(người dùng là tên của mảng)

Array=>
 [0] => (array)
   'user' => 'john'
   'age' => '23'
 [1] => (array)
  'user' => 'jane'
  'age' => '20'
 [2]=> (array)
  'user' => 'john'
  'age' => '23'

và bạn muốn xóa các bản sao ... thì:

$serialized = array();
for ($i=0; $i < sizeof($users); $i++) { 
  $test = in_array($users['user'], $serialized);
    if ($test == false) {
      $serialized[] = $users['user'];
    }
 }

có thể là một giải pháp: P


1

Một giải pháp dễ đọc, có lẽ không hiệu quả nhất:

function arrayUnique($myArray){
    if(!is_array($myArray))
        return $myArray;

    foreach ($myArray as &$myvalue){
        $myvalue=serialize($myvalue);
    }

    $myArray=array_unique($myArray);

    foreach ($myArray as &$myvalue){
        $myvalue=unserialize($myvalue);
    }

    return $myArray;

} 

1

Như mọi người đang nói array_unique()là rất chậm, đây là đoạn trích tôi sử dụng cho mảng đa chiều một cấp.

$serialized_array = array_map("serialize", $input);

foreach ($serialized_array as $key => $val) {
     $result[$val] = true;
}

$output = array_map("unserialize", (array_keys($result)));

Tham khảo ghi chú đóng góp của người dùng đầu tiên của array_unique() trang chức năng trong php.net


Anuj, bạn có thể vui lòng chỉnh sửa câu trả lời của bạn? Có một lỗi. Nó sẽ kết thúc $output = array_map('unserialize', array_keys($result));
bàn

@keyboardSmasher cảm ơn bạn đã đóng góp. Tôi đã thực hiện các thay đổi và bây giờ nó hoạt động. :)
Anuj

1

Rất nhiều người hỏi tôi làm thế nào để tạo ra mảng đa chiều độc đáo. Tôi đã tham khảo từ bình luận của bạn và nó giúp tôi.

Trước hết, Cảm ơn @jeromegamez @daveilers cho giải pháp của bạn. Nhưng mỗi khi tôi đưa ra câu trả lời, họ lại hỏi tôi cách 'tuần tự hóa' và 'không xác định' này hoạt động như thế nào. Đó là lý do tại sao tôi muốn chia sẻ lý do của việc này với bạn để nó sẽ giúp nhiều người hiểu hơn về khái niệm này.

Tôi đang giải thích lý do tại sao chúng tôi sử dụng 'tuần tự hóa' và 'hủy xác định' theo các bước:

Bước 1: Chuyển đổi mảng đa chiều thành mảng một chiều

Để chuyển đổi mảng đa chiều thành mảng một chiều, trước tiên hãy tạo biểu diễn luồng byte của tất cả các phần tử (bao gồm các mảng lồng nhau) bên trong mảng. Hàm serialize () có thể tạo biểu diễn luồng byte của một giá trị. Để tạo biểu diễn luồng byte của tất cả các phần tử, hãy gọi hàm serialize () bên trong hàm Array_map () dưới dạng hàm gọi lại. Kết quả sẽ là một mảng một chiều cho dù mảng đa chiều có bao nhiêu cấp.

Bước 2: Làm cho các giá trị là duy nhất

Để làm cho mảng một chiều này là duy nhất, hãy sử dụng hàm Array_unique ().

Bước 3: Hoàn nguyên nó về mảng đa chiều

Mặc dù mảng này là duy nhất, các giá trị trông giống như biểu diễn luồng byte. Để hoàn nguyên nó trở lại mảng nhiều chiều, hãy sử dụng hàm unserialize ().

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

Cảm ơn một lần nữa cho tất cả điều này.


0

Một thay thế để nối tiếp và duy nhất

$test = [
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
];

$result = array_reduce(
    $test,
    function($carry,$item){
        if(!in_array($item,$carry)) {
            array_push($carry,$item);
        }
        return $carry;
    },
    []
);

var_dump($result);

/*
 php unique.php
array(3) {
    [0] =>
        array(2) {
            [0] =>
                string(3) "abc"
            [1] =>
                string(3) "def"
        }
    [1] =>
        array(2) {
            [0] =>
                string(3) "ghi"
            [1] =>
                string(3) "jkl"
        }
    [2] =>
        array(2) {
              [0] =>
                  string(3) "mno"
              [1] =>
                  string(3) "pql"
        }
}

* /


0

Nếu bạn có một mảng như thế này

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => b
),
[3] => array
(
    [subject] => d
    [object] => c
),
[4] => array
(
    [subject] => c
    [object] => a
),
[5] => array
(
    [subject] => c
    [object] => d
)
)

và bạn muốn có được các mảng như thế này:

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => c
)
)

hoặc là

data = array
(
[0] => array
(
    [subject] => d
    [object] => b
),
[1] => array
(
    [subject] => c
    [object] => a
),
[2] => array
(
    [subject] => c
    [object] => d
)
)

một đoạn mã sau có thể giúp

    $data1 = array();
    $data1 = $data;
    for($q=0;$q<count($data);$q++)
    {
            for($p=0;$p<count($data1);$p++)
            {
                    if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"]))
                    {
                            $data1[$p]["subject"] = $data[$q]["subject"];
                            $data1[$p]["object"] = $data[$q]["object"];
                    }
            }
    }
    $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1))));
    $data = $data1;

0

Tôi đã suy nghĩ vấn đề này rất nhiều và đã xác định rằng giải pháp tối ưu phải tuân theo hai quy tắc.

  1. Đối với khả năng mở rộng, sửa đổi các mảng tại chỗ; không sao chép vào một mảng mới
  2. Đối với hiệu suất, mỗi so sánh chỉ nên được thực hiện một lần

Với ý nghĩ đó và đưa ra tất cả các yêu cầu của PHP, dưới đây là giải pháp tôi đã đưa ra. Không giống như một số câu trả lời khác, nó có khả năng loại bỏ các yếu tố dựa trên bất kỳ khóa nào bạn muốn. Mảng đầu vào dự kiến ​​là các phím số.

$count_array = count($input);
for ($i = 0; $i < $count_array; $i++) {
    if (isset($input[$i])) {
        for ($j = $i+1; $j < $count_array; $j++) {
            if (isset($input[$j])) {
                //this is where you do your comparison for dupes
                if ($input[$i]['checksum'] == $input[$j]['checksum']) {
                    unset($input[$j]);
                }
            }
        }
    }
}

Hạn chế duy nhất là các phím không theo thứ tự khi việc lặp hoàn thành. Đây không phải là vấn đề nếu sau đó bạn chỉ sử dụng các vòng lặp foreach, nhưng nếu bạn cần sử dụng vòng lặp for, bạn có thể đặt $input = array_values($input);sau phần trên để đánh số lại các phím.


0

Dựa trên Câu trả lời được đánh dấu là chính xác, thêm câu trả lời của tôi. Mã nhỏ được thêm vào chỉ để thiết lập lại các chỉ số-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
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.