วิธีการลบค่าที่ซ้ำกันออกจากอาร์เรย์หลายมิติใน PHP


306

ฉันจะลบค่าที่ซ้ำกันออกจากอาร์เรย์หลายมิติใน PHP ได้อย่างไร

อาร์เรย์ตัวอย่าง:

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
    )

)

คำตอบ:


637

นี่คือวิธีอื่น ไม่มีการบันทึกตัวแปรกลาง

เราใช้สิ่งนี้เพื่อแยกผลลัพธ์ที่ซ้ำกันจากการสืบค้นที่ซ้อนกันหลายแบบ

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

23
เนื่องจาก unserialize นี้จะช้าลงและช้าลงขนาดใหญ่และซับซ้อนมากขึ้นอาร์เรย์คือ มีเหตุผลที่ฉันใช้ array_intersect_key (ครึ่งปีก่อนคำตอบนี้)
OIS

11
@OIS เพิ่งทดสอบมันมี typo แต่มันใช้งานได้ดีขอบคุณเพื่อน!: $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array)));
trevorkavanaugh

3
ถ้าคุณต้องการดัชนีต่อเนื่องให้ใช้ array_values ​​เช่น $ input = array_values ​​(array_map ("unserialize", array_unique (array_map ("serialize", $ input))))
lbsweek

4
ทุกวันนี้คุณอาจเลือกใช้ json_encode และ json_decode แทนการทำให้เป็นอนุกรมของ PHP ควรมีประโยชน์สำหรับค่าที่มีให้และคุณไม่ได้เรียกใช้รายละเอียดการทำให้เป็นอนุกรมของ PHP ที่ทำให้เป็นอันดับ / unserialize จัดส่งด้วยและส่วนใหญ่ไม่ต้องการ
hakre

2
ระวังว่าจะแตกต่างจากserialize(array('a' => '1', 'b' => '1')) serialize(array('b' => '1', 'a' => '1'))ตัวเลือกนี้จะล้มเหลวสำหรับใช้เป็นอาร์เรย์หรือsets (hash)maps
Andras Gyomrey

240

ตั้งแต่ 5.2.9 คุณสามารถใช้array_unique()หากคุณใช้งานSORT_REGULARธงดังนี้:

array_unique($array, SORT_REGULAR);

สิ่งนี้ทำให้ฟังก์ชั่นเปรียบเทียบองค์ประกอบเพื่อความเท่าเทียมราวกับ$a == $bกำลังถูกใช้ซึ่งเหมาะสำหรับกรณีของคุณ

เอาท์พุต

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

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

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

)

อย่างไรก็ตามโปรดทราบว่าเอกสารระบุว่า:

array_unique() ไม่ได้มีวัตถุประสงค์เพื่อทำงานในอาร์เรย์หลายมิติ


2
ฉันคิดว่านี่เป็นวิธีแก้ปัญหาที่รวดเร็วและชัดเจนกว่าโซลูชันที่ยอมรับ! ให้คะแนนสำหรับอันนี้! :) อืมบนเว็บไซต์ PHPเราจะเห็นว่ามันไม่ได้เป็นอย่างรวดเร็วเป็นฉันคิดว่า ...
Andron

4
แปลกที่การใช้การตั้งค่าสถานะ SORT_REGULAR ใช้งานไม่ได้สำหรับฉันเพื่อลบอาร์เรย์ที่ซ้ำกัน
Stefan

4
@ สเตฟานคุณพูดถูก; ดูเหมือนจะไม่ให้ผลลัพธ์ที่ถูกต้อง แต่อาจเป็นข้อผิดพลาดเพราะใช้งานกับ PHP 7 = /
Ja͢ck

4
สิ่งนี้ดูเหมือนว่าจะทำงานในกรณีของฉัน แต่มีใครสนใจข้อความนี้ในเอกสาร array_unique () หรือไม่ php.net/manual/en/…
Arleigh Hix

2
@ แจ็คคุณพูดถูกนี่เป็นข้อผิดพลาด ณ PHP 5.6.23: eval.in/645675แต่ได้รับการแก้ไขแล้วเป็น PHP 7.0.8: eval.in/645676
Zack Morris

63

ฉันมีปัญหาที่คล้ายกัน แต่ฉันพบวิธีแก้ปัญหาการทำงาน 100%

<?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
คำถามนี้ตอบคำถามที่แตกต่าง ดูที่นี่: stackoverflow.com/questions/4585208/…
OIS

ฟังก์ชั่นที่ยอดเยี่ยม! และในกรณีที่คุณจัดการกับวัตถุ: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox

35

อีกวิธีหนึ่ง จะเก็บกุญแจไว้เช่นกัน

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

สำหรับอาร์เรย์ขนาดใหญ่วิธีนี้มักจะเร็วกว่าคำตอบที่ยอมรับอย่างน้อย 50%
Lorien Brune

21

ความคิดเห็นของผู้ใช้ในเอกสารarray_unique ()มีวิธีแก้ไขปัญหามากมาย นี่คือหนึ่งในนั้น:

kenrbnsn ที่ rbnsn dot com
27-Sep-2005 12:09

อีกหนึ่ง Array_Unique สำหรับอาร์เรย์ที่มีหลายระดับ ฉันได้ทดสอบสิ่งนี้กับอาร์เรย์สอง demensioned แล้วเท่านั้น แต่มันอาจจะทำให้เป็นแบบทั่วไปมากขึ้นหรือใช้การเรียกซ้ำ

ฟังก์ชันนี้ใช้ฟังก์ชัน serialize, array_unique และ unserialize เพื่อทำงาน


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

นี้เป็นจากhttp://ca3.php.net/manual/en/function.array-unique.php#57202


18

หาก "ลบรายการที่ซ้ำกัน" หมายถึง "ลบรายการที่ซ้ำกัน แต่ให้มีรายการนั้น" วิธีแก้ไขอาจใช้array_unique(...)กับ "คอลัมน์ตัวระบุ" ก่อนแล้วจึงลบคีย์ทั้งหมดในอาร์เรย์เดิมที่ถูกลบออกจากอาร์เรย์คอลัมน์ :

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

ผลลัพธ์คือ:

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

นี่จะเป็นการลบชื่อที่ซ้ำกันออกจากอาร์เรย์ โดดเด่นด้วยกุญแจ


ตรวจสอบว่า$arrayคีย์เริ่มต้นที่ "0" อาจเป็นไปได้$arrayว่าปุ่มเริ่มต้นที่หมายเลขอื่นหาก$arrayเป็นผลมาจากการจัดการอาร์เรย์ก่อนหน้า ใช้array_valuesเพื่อรีเซ็ตคีย์กลับเป็น "0"
stevevance


4

เพียงใช้ตัวเลือก SORT_REGULAR เป็นพารามิเตอร์ตัวที่สอง

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR ใช้งานได้เฉพาะใน PHP 7 เพราะ PHP 5 มีข้อผิดพลาด (แม้ว่า @ r3wt นั้นถูกต้องตามเอกสาร) ดูความคิดเห็นของฉันในคำตอบสำหรับตัวอย่างที่เรียกใช้stackoverflow.com/questions/307674/ …
Zack Morris

ทำไมคุณต้องเพิ่มสิ่งนี้ มันเหมือนกับคำตอบนี้ซึ่งเก่าแก่กว่าของคุณมากกว่าหนึ่งปี: stackoverflow.com/a/18373723/870729
random_user_name

3

หากคุณต้องการกำจัดรายการที่ซ้ำกันบนคีย์เฉพาะเช่นรหัส mysqli นี่คือ funciton ที่เรียบง่าย

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

คะแนนโบนัส คุณสามารถผ่านอาร์เรย์ของคีย์และเพิ่มด้านหน้าด้านนอก แต่จะช้าลง 2 เท่าต่อคีย์เพิ่มเติม


3

วิธีที่ง่ายและตรรกะในการที่ไม่เหมือนใครอาเรย์หลายมิติมีดังต่อไปนี้

หากคุณมีอาร์เรย์เช่นนี้:

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

ใช้foreachเพื่อแก้ปัญหานี้:

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

มันจะให้ผลลัพธ์ดังต่อไปนี้:

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

และถ้าคุณต้องการจัดลำดับของคีย์ใหม่

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

การดำเนินการนี้จะทำให้คุณได้รับการจัดเรียงค่าคีย์ดังนี้:

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

ฉันหวังว่านี่จะล้างทุกอย่าง


2

หากคุณมีอาร์เรย์ดังนี้:

(ผู้ใช้คือชื่อของอาร์เรย์)

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

และคุณต้องการลบข้อมูลซ้ำ ... จากนั้น:

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

สามารถเป็นทางออกได้: หน้า


1

โซลูชันที่อ่านง่ายอาจไม่ใช่วิธีที่มีประสิทธิภาพที่สุด:

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

ในขณะที่ผู้คนกำลังพูดarray_unique()ช้ามากนี่คือตัวอย่างที่ฉันใช้สำหรับอาร์เรย์หลายมิติในระดับหนึ่ง

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

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

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

การอ้างอิงผู้ใช้ครั้งแรกมีส่วนร่วมทราบarray_unique() หน้าฟังก์ชั่นใน php.net


อย่างไรก็ตาม, คุณช่วยแก้ไขคำตอบของคุณได้ไหม? มีข้อผิดพลาด มันควรจะจบลง $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasher ขอบคุณสำหรับการป้อนข้อมูลของคุณ ฉันทำการเปลี่ยนแปลงและตอนนี้ก็ใช้งานได้ :)
Anuj

1

มีคนมากมายถามฉันถึงวิธีสร้างอาร์เรย์หลายมิติที่ไม่ซ้ำใคร ฉันได้รับการอ้างอิงจากความคิดเห็นของคุณและมันช่วยฉันได้

ก่อนอื่นขอขอบคุณ @jeromegamez @Daveilers สำหรับวิธีแก้ปัญหาของคุณ แต่ทุกครั้งที่ฉันให้คำตอบพวกเขาถามฉันว่า 'serialize' และ 'unserialize' นี้ทำงานอย่างไร นั่นเป็นเหตุผลที่ฉันต้องการแบ่งปันเหตุผลนี้กับคุณเพื่อที่จะช่วยให้ผู้คนจำนวนมากเข้าใจแนวคิดที่อยู่เบื้องหลัง

ฉันกำลังอธิบายว่าเพราะเหตุใดเราจึงใช้ 'ทำให้เป็นอันดับ' และ 'ไม่ระบุ' ในขั้นตอน:

ขั้นตอนที่ 1: แปลงอาเรย์หลายมิติเป็นอาเรย์หนึ่งมิติ

ในการแปลงอาร์เรย์หลายมิติให้เป็นอาร์เรย์หนึ่งมิติขั้นแรกให้สร้างการแทนค่าสตรีมไบต์ขององค์ประกอบทั้งหมด (รวมถึงอาร์เรย์ที่ซ้อนกัน) ภายในอาร์เรย์ ฟังก์ชั่นเป็นอันดับ () สามารถสร้างการเป็นตัวแทนไบต์ของค่า ในการสร้างการเป็นตัวแทนไบต์ขององค์ประกอบทั้งหมดให้เรียกฟังก์ชั่นอนุกรม () ภายในฟังก์ชั่น array_map () เป็นฟังก์ชั่นการโทรกลับ ผลลัพธ์จะเป็นอาร์เรย์หนึ่งมิติไม่ว่าจะมีอาร์เรย์หลายมิติหลายระดับ

ขั้นตอนที่ 2: ทำให้ค่าไม่ซ้ำกัน

เพื่อทำให้อาเรย์หนึ่งมิติมีความเป็นเอกลักษณ์ให้ใช้ฟังก์ชัน array_unique ()

ขั้นตอนที่ 3: แปลงกลับเป็นอาร์เรย์หลายมิติ

แม้ว่าตอนนี้อาร์เรย์จะมีค่าไม่ซ้ำกัน แต่ค่าดูเหมือนเป็นตัวแทนไบต์ ในการแปลงกลับเป็นอาเรย์หลายมิติให้ใช้ฟังก์ชัน unserialize ()

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

ขอบคุณอีกครั้งสำหรับทั้งหมดนี้


0

ทางเลือกในการทำให้เป็นอันดับและไม่ซ้ำกัน

$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

หากคุณมีอาร์เรย์เช่นนี้

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

และคุณต้องการได้รับอาร์เรย์ดังนี้:

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

หรือ

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

รหัสต่อไปนี้สามารถช่วยได้

    $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

ฉันได้รับปัญหานี้อย่างมากและได้พิจารณาแล้วว่าทางออกที่ดีที่สุดควรเป็นไปตามกฎสองข้อ

  1. เพื่อความยืดหยุ่นให้ปรับเปลี่ยนอาร์เรย์ในตำแหน่ง ไม่มีการคัดลอกไปยังอาร์เรย์ใหม่
  2. สำหรับประสิทธิภาพการเปรียบเทียบแต่ละครั้งควรทำเพียงครั้งเดียว

เมื่อคำนึงถึงสิ่งนี้และได้รับประโยชน์ทั้งหมดของ PHP ด้านล่างเป็นวิธีแก้ปัญหาที่ฉันคิดขึ้นมา ต่างจากคำตอบอื่น ๆ บางคำ แต่มีความสามารถในการลบองค์ประกอบตามคีย์ที่คุณต้องการ คาดว่าอาร์เรย์อินพุตจะเป็นคีย์ตัวเลข

$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]);
                }
            }
        }
    }
}

ข้อเสียเปรียบเพียงอย่างเดียวคือกุญแจไม่ได้อยู่ในลำดับเมื่อการวนซ้ำเสร็จสมบูรณ์ นี่ไม่ใช่ปัญหาหากคุณใช้ลูป foreach ในแต่ละครั้ง แต่ถ้าคุณจำเป็นต้องใช้ลูป for for loop คุณสามารถใส่$input = array_values($input);เครื่องหมายด้านบนเพื่อกำหนดหมายเลขใหม่


0

จากคำตอบที่ทำเครื่องหมายว่าถูกต้องให้เพิ่มคำตอบของฉัน มีการเพิ่มโค้ดขนาดเล็กเพื่อรีเซ็ตดัชนี -

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.