Как удалить дублированный 2-мерный массив в PHP? - PullRequest
4 голосов
/ 08 августа 2009

У меня есть идея из предыдущих постов, в которой говорилось о создании значения хеш-функции для каждого массива $ [$ i], а затем сравнивании хеш-функции для получения уникального массива, но я не знаю, что именно могу сделать .

Мой пример массива данных:

$arr[] = array(0,1,2,3);
$arr[] = array(4,5,2,1);
$arr[] = array(0,0,0,0);
$arr[] = array(0,1,2,3);

Я ожидал возвращения:

$arr[] = array(0,1,2,3);
$arr[] = array(4,5,2,1);
$arr[] = array(0,0,0,0);

Может кто-нибудь выложить мне функцию для этой цели?

Большое спасибо!

Ответы [ 5 ]

17 голосов
/ 08 августа 2009

Быстро и просто:

$arr = array_map('unserialize', array_unique(array_map('serialize', $arr)));
0 голосов
/ 08 августа 2009

Это зависит от того, есть ли у вас ресурсы для хранения большего массива в памяти (поэтому, в основном, это зависит от того, хотите ли вы только уникальные значения, чтобы предотвратить его вздутие во время цикла, или вам нужен только конечный результат массив уникальных значений.

Для всех примеров я предполагаю, что вы получаете значения для ввода в большой массив из какого-то внешнего источника, такого как запрос MySQL.

Чтобы предотвратить ввод дубликатов в основной массив:

Вы можете создать два массива, один со значениями в виде строки, другой со значениями в качестве фактических значений массива.

while($row = $results->fetch_assoc) {
     $value_string = implode("," $row);
     if(in_array($value_string, $check_array) {
         $check_array[] = $value_string;
         $master_array[] = $row;
      }
 }

В приведенном выше примере он просто видит, находится ли строковая версия вашего набора данных в массиве наборов строковых данных, уже перебранных. В результате вы получите большие издержки с двумя массивами, но ни один из них никогда не получит повторяющихся значений.

Или, как уже упоминалось, я уверен, что есть array_unique, который происходит после ввода всех данных. Изменяя приведенный выше пример, вы получаете

while($row = $results->fetch_assoc) {
     $master_array[] = $row;
   }
 $master_array = array_unique($master_array);
0 голосов
/ 08 августа 2009

Вот еще одна идея. Опять же, не очень элегантно, но может быть довольно быстро. Это похоже на вторую часть Chacha102, хотя было бы быстрее, если бы у вас были только целочисленные значения во вложенных массивах.

// implode the sub arrays
$tmpArray = array();
foreach ($arr as $key => $array) {
    $tmpArray[$key] = implode(',', $array);
}

// get only the unique values
$tmpArray = array_unique($tmpArray);

// explode the values
$arr = array();
foreach ($tmpArray as $key => $string) {
    $arr[$key] = explode(',', $string);
}
0 голосов
/ 08 августа 2009

Хеширование - это хорошая идея, в среднем решение будет O (n)

По сути, вы перебираете $ arr и создаете хэш всего массива, а затем сравниваете его с предыдущими хэшами, которые вы видели (это O (1) с использованием isset () или O (m), если быть точным) где m - количество элементов во внутреннем массиве). и если есть столкновение, вы сравниваете фактические элементы массива. обычно столкновение означает, что вы уже видели этот массив, и он является дубликатом, но это не гарантировано. Вот некоторые psuedo PHP, который реализует этот алгоритм.

function mkhash($array = array()) {
   $hash = "";
   foreach ($array as $element) {
      $hash .= md5($element);
   }
}

$seen = array();
$newArray = array();
foreach($arr as $elementArray) {
   $hash = mkhash($elementArray); 
   if(!isset($seen[$hash])) {
     $newArray[] = $elementArray;
     $seen[$hash] = $elementArray;
   } else if(count(array_diff($elementArray, $seen[$hash])) > 0) {
      $newArray[] = $elementArray; //this is true if two different arrays hashed to the same element
   }
}

Метод хеширования сложнее реализовать, и правильно обрабатывать коллизии довольно сложно, поэтому есть O (nlogn).

O (nlogn) способ сделать это - отсортировать массив

$arr = array_multisort($arr); //O(nlogn)

И тогда все, что вам нужно сделать, это сравнить соседние массивы, чтобы увидеть, являются ли они дубликатами

Конечно, вы можете просто использовать подход O (n ^ 2) и сравнить каждый внутренний массив с любым другим внутренним массивом ...

РЕДАКТИРОВАТЬ: о, и вот еще одна идея O (n), вы можете рекурсивно построить дерево, используя ключи массива, которые сопоставляются с другими массивами, так что вы получите глубокий массив уровня m, где m - самый длинный внутренний массив, который у вас есть , Каждая ветвь дерева представляет собой уникальный внутренний массив. Конечно, вам придется написать некоторый служебный код для преобразования дерева обратно в 2D-массив, так что вы не увидите выигрыша в производительности, пока мощность вашего ввода не станет очень большой!

0 голосов
/ 08 августа 2009
foreach($arr as $key => $value)
{
   foreach($arr as $key2 => $value2)
   {
      if($value2 == $value && $key != $key2)
       {
          unset($arr[$key]);
       }
    }
}

Это не самый элегантный метод, но он делает именно то, что вам нужно. Проблема в том, что вы не можете использовать array_unique рекурсивно.

Это еще один способ из комментариев к документации PHP.net (там есть большие фрагменты кода)

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; 

} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...