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
직렬화 해제로 인해 어레이가 더 크고 더 복잡합니다. array_intersect_key를 사용하는 이유가 있습니다 (이 답변 전 반년).
OIS

11
@OIS는 방금 테스트했지만 오타가 있었지만 작동합니다 .. 고마워 친구 : $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ( 'serialize', $ array)));
trevorkavanaugh

3
인덱스를 계속 사용하려면 array_values를 사용하십시오. 즉 $ input = array_values ​​(array_map ( "unserialize", array_unique (arser_map ( "serialize", $ input))));
lbsweek

4
요즘에는 PHP 직렬화 대신 json_encode 및 json_decode를 선택했을 것입니다. 제공되는 값에 대한 혜택을해야 하고 당신은 직렬화 / 때 unserialize 배송 및 대부분 원치 않는 것을 PHP 직렬화 세부 사항으로 실행되지 않습니다.
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
@Jack 당신은 맞습니다. 이것은 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 () 문서 에 대한 사용자 의견에는 이에 대한 많은 솔루션이 있습니다. 다음 중 하나입니다.

rbnsn 닷컴에서 kenrbnsn
2005 년 9 월 27 일 12시 9 분

다중 부담 배열을위한 또 다른 Array_Unique. 나는 이것을 2 차원 배열에서만 테스트했지만 더 일반화하거나 재귀를 사용하도록 만들 수 있습니다.

이 함수는 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
(@ r3wt이 문서에 따라 정확하지만) PHP 5 버그를 가지고 있기 때문에 SORT_REGULAR 만, 실행 가능한 예제에 대한 대답에 내 의견을 참조 PHP 7에서 작동 stackoverflow.com/questions/307674/...
잭 모리스

왜 이것을 추가 하시겠습니까? : 그것은이 년 이상 당신보다 나이가 대답과 동일합니다 stackoverflow.com/a/18373723/870729
random_user_name

3

mysqli id와 같은 특정 키에서 중복을 제거 해야하는 경우 간단한 기능은 다음과 같습니다.

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

보너스 포인트 여러 키를 전달하고 외부 foreach를 추가 할 수 있지만 추가 키당 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'];
    }
 }

해결책이 될 수 있습니다 : P


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

php.net 의 첫 페이지 사용자가 함수 페이지 참고에 기여array_unique()


Anuj, 답을 편집 해 주시겠습니까? 버그가 있습니다. 그것은 끝날 것이다 $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasher 입력 해 주셔서 감사합니다. 나는 변경했고 이제는 작동합니다. :)
Anuj

1

많은 사람들이 고유 한 다차원 배열을 만드는 방법을 물었습니다. 나는 당신의 의견을 참조하여 도움이됩니다.

우선 솔루션을 제공하는 @jeromegamez @daveilers에게 감사드립니다. 그러나 내가 대답 할 때마다 그들은이 '직렬화'와 '직렬화 해제'가 어떻게 작동하는지 물었습니다. 그렇기 때문에 더 많은 사람들이이 개념을 이해하는 데 도움이되도록이 이유를 여러분과 공유하고 싶습니다.

왜 우리가 'serialize'와 'serialize'를 단계적으로 사용하는지 설명하고 있습니다.

1 단계 : 다차원 배열을 1 차원 배열로 변환

다차원 배열을 1 차원 배열로 변환하려면 먼저 배열 내부의 모든 요소 (중첩 배열 포함)의 바이트 스트림 표현을 생성하십시오. serialize () 함수는 값의 바이트 스트림 표현을 생성 할 수 있습니다. 모든 요소의 바이트 스트림 표현을 생성하려면 array_map () 함수 내에서 serialize () 함수를 콜백 함수로 호출하십시오. 결과는 다차원 배열의 레벨 수에 관계없이 1 차원 배열이됩니다.

2 단계 : 값을 고유하게 만들기

이 1 차원 배열을 고유하게 만들려면 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 루프를 사용해야하는 $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.