2013-02-10 16 views
12
$array = array(1, '1a', '1'); 
var_export(array_unique($array, SORT_REGULAR)); 
  • Rezultat: array (0 => 1, 2 => '1')
  • W podręczniku PHP: SORT_REGULAR - porównuj elementy normalnie (nie zmienia typów).

Jaka jest logika tego? Dlaczego lub w jaki sposób wykluczono "1a"?array_unique SORT_REGULAR flag

Odpowiedz

13

Dzieje się tak dlatego array_unique prace first sorting the values as strings, następnie iterating ponad posortowanej tablicy i dla każdej wartości wyłączającej z wyniku wszystkich kolejnych wartości, które porównują równa nim.

Funkcja porównywania dla "porównania równości" powyżej jest wybierana zgodnie z drugim parametrem, który dla SORT_REGULAR jest taki sam jak sprawdzanie równości z ==.

To zachowanie powoduje wiele kupek. Ponieważ sortowanie to quicksort, jest niestabilne. Dlatego sortowanie tablicy zawierającej zarówno 1 jak i '1' nie daje żadnej gwarancji, która z nich będzie pierwsza w wyniku. Oznacza to, że array_unique może wydawać się dowolnie "preferować" 1 w niektórych przypadkach i '1' w innych.

Jednak szaleństwo kontynuuje: uważają, że jeżeli rodzaj produkuje [1, '1', '1a'] następnie '1a' będzie nie zostać ujęte w wyniku (porównuje równa 1), podczas gdy rodzaj produkuje ['1', 1, '1a'] to będzie być włączone (to robi nie można porównać z ciągiem znaków '1')!

+0

Czy ta iteracja występuje tylko raz? Ponieważ wtedy powinniśmy uzyskać zduplikowane wartości, jeśli inny '1' jest zawarty po' 5' –

+0

@OneTrickPony: Nie powiedziałem wyraźnie, że tablica jest sortowana jako pierwsza (dokumentacja robi). Ale z drugiej strony jest to bardzo ważne, ponieważ sortowanie nie jest stabilne (quicksort), więc pozwól mi nieco rozszerzyć odpowiedź. – Jon

+0

@OneTrickPony: Właściwie to działa nieco inaczej niż sądziłem - i prawdopodobnie nie będziesz zaskoczony tym, że zachowanie nie może być przewidziane w takich przypadkach, ponieważ, cóż, PHP. – Jon

4

Jeśli chcesz uzyskać trochę bardziej techniczny, możesz zobaczyć źródło.

Flaga PHP_SORT_REGULAR po prostu mówi array_unique, aby powrócić do standardowego operatora porównania (==).

Można to zobaczyć w źródle dla array_unique który wykorzystuje php_set_compare_func:

static void php_set_compare_func(int sort_type TSRMLS_DC) /* {{{ */ 
{ 
switch (sort_type & ~PHP_SORT_FLAG_CASE) { 
... 
    case PHP_SORT_REGULAR: 
    default: 
     ARRAYG(compare_func) = compare_function; 
     break; 
} 

Gdzie compare_func jest tylko standard comparison function.

To prawdopodobnie błąd w dokumentacji, bardziej niż cokolwiek innego. Komentarz w dokumentacji jest nieco mylący:

... równe wtedy i tylko wtedy jeśli (string) $ elem1 === (string) $ elem2

Jeżeli obie wartości są rzutowane na smyczki , następnie === jest zbędne, ale prowadzi do założenia, że ​​SORT_REGULAR dokonuje porównania typów.