2010-05-14 15 views

Odpowiedz

2

array_intersect() zwraca tablicę zawierającą wszystkie wartości tablicy 1, które występują we wszystkich argumentach.

Więc co znaczy występuje w tym kontekście (exacly ta funkcja), znalazłem na php.net Moja odpowiedź:

Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same.

Wtedy nie można używać go na tablicy obiekty, jeśli obiekty nie implementują unikatowej konwersji na ciąg.

+4

To niedorzeczne. Istnieją co najmniej trzy sposoby przekształcania obiektów w ciąg znaków. Mogą to być klasy PHP i implementować __toString, mogą mieć obsadę obsługującą obsadę, która akceptuje IS_STRING i mogą mieć procedurę obsługi, która zwraca zval, który jest konwertowalny na ciąg znaków. – Artefacto

+0

+1 @Artefakto, prześlij odpowiedź z przykładem za pomocą dowolnych obiektów i array_intersect(). – Dolph

+0

Jeśli twoje obiekty nie implementują unikatowej konwersji na łańcuch. – Svisstack

1

Poprawnym sposobem sprawdzenia, czy dwa obiekty są równe, jest użycie ==. Dlatego:

array_uintersect($arr1, $arr2, function ($a1, $a2) { return $a1 == $a2; }); 
+0

to nie działa. Masz inne kodowanie? –

+1

Musisz być bardziej szczegółowy. Co nie działa? Czy są jakieś komunikaty o błędach? Jakie komunikaty o błędach? Wynik nie jest oczekiwany? Czego oczekiwano? Co dostałeś? – Artefacto

+1

To nie działa, ponieważ array_unintersect potrzebuje funkcji porównania, aby zwrócić 1, -1 lub 0. Zobacz tutaj pełne wyjaśnienie i przykład http://php.net/manual/en/function.array-uintersect. php # 72841 – Tim

6

ładny toString funkcja jest już wdrożony i jest nazywany serialize;) tak

array_map(
    'unserialize', 
    array_intersect(
     array_map(
      'serialize', 
      $obj1 
     ), 
     array_map(
      'serialize', 
      $obj2 
     ) 
    ) 
); 

zrobi pracę przykład wspomniano wyżej nie działa bo array_intersect praca tylko z łańcuchami jak ktoś wspomniałem także

+0

doskonały hack. działa idealnie :) – yitwail

+0

przy dalszej myśli, nie jest to odpowiednie, jeśli obiekty mają metody. kiedy serializujesz, tracisz metpds, więc zachowujesz tylko właściwości – yitwail

2

Miałem podobny problem kilka dni temu, podczas gdy te są odpowiedzi na właściwej ścieżce; Kiedyś je wypracować następujące:

Od odpowiedzi Artefacto za return $obj1 == $obj2 tak naprawdę nie działała, więc napisałem prostą funkcję porównawczą (w zasadzie dostaje MD5 odcinkach obiektu i porównuje to):

function object_compare($obj1, $obj2){ 
    $md5 = function($obj){ 
    return md5(serialize($obj)); 
    }; 
    return strcmp($md5($obj1), $md5($obj2)); 
} 

Wtedy to jut kwestia nazywając array_uintersect z naszej funkcji porównawczej dostać przecięciach:

# $array1/$array2 are the array of objects we want to compare 
return array_uintersect($array1, $array2, 'object_compare'); 

W moim przypadku, miałem nieznany/dynamiczną tablicę obiektów, więc wziąłem go o krok dalej, więc don” t muszą zadeklarować array_uintersect($array1, $array2, ...) specjalnie - ale po prostu być w stanie przejść w tablicy tablic (obiektów):

# $multiarray_of_objects is our array of arrays 
$multiarray_of_objects[] = 'object_compare'; 
return call_user_func_array('array_uintersect', $multiarray_of_objects); 

prostu musisz pamiętać, aby przekazać w odniesieniu do naszej zwrotnego funkcja/porównawcza jako ostatni ciąg w tablicy. Działa jak marzenie!

+0

Z powodu pracy w klasie kontrolera, nie mogłem tego zrobić tak, ale używanie twojego podejścia z formatem Artefacto działało jak czar. – Magnanimity

+0

W klasie 'return array_uintersect ($ array1, $ array2, 'self :: object_compare');' powinno działać, lub nawet 'ClassName :: object_compare', ale pamiętaj, że musi to być funkcja klasy publicznej. – Atari

0

Używam array_udiff do wdrożenia array_intersect dla object array.

function diff($a, $b) { 
if($a === $b) { 
    return 0; 
} else { 
    return 1;} 
} 

$array_1 = array('a', 'b', 'c');  

$array_2 = array('c', 'd','e');  

$array = array_udiff($array_1, array_udiff($array_1, $array_2, 'diff'),'diff'); 

var_dump($array); 
return array(1) { [2]=> string(1) "c" } 

Możesz mieć własną funkcję diff dla dowolnego schematu.

8

można używać w połączeniu z array_uintersect spl_object_hash patrz przykład:

array_uintersect($a, $b, function($a, $b) { 
     return strcmp(spl_object_hash($a), spl_object_hash($b)); 
    }); 

gdzie „$ a” i „$ b” są tablice niektórych obiektów, które chcesz przecinają.

+0

Ładne rozwiązanie. Dla współczesnych czytelników: w php7, 'strcmp()' można zastąpić operatorem '<=>', takim jak to: 'return spl_object_hash ($ a) <=> spl_object_hash ($ b);' –

-1

Prawidłowe rozwiązanie byłoby:

array_uintersect($arr1, $arr2, function ($a1, $a2) { return $a1 != $a2; }); 

Zanotuj = w funkcji wywołania zwrotnego, w przeciwieństwie do odpowiedzi z @Artefacto!. Na podstawie dokumentacji array_uintersect funkcja wywołania zwrotnego musi zwrócić wartość 0 (fałsz), jeśli elementy tablicy są równe.

+0

To jest niepotrzebny typ hackowania, funkcja zwrotna powinna zwracać liczbę całkowitą (-1, 0, 1), jeśli pierwsza wartość jest mniejsza, równa lub większa od drugiej, podobnie jak w przypadku funkcji sortowania. Niejawny typecast wartości false wynoszący 0 zmyli czytelników twojego kodu. – amik

0

Tylko dla kompletności: Zaimplementuj metodę __toString() w obiekcie zwracając unikalną wartość. W przypadku jednostek bazy danych może to być tak proste, jak zwrócenie pełnej nazwy klasy, która została dodana z identyfikatorem rekordu. Ale może być też dowolnie skomplikowana, wykonując haszowanie lub nawet gorsze rzeczy.

Moim zdaniem obowiązkiem klasy jest serializacja lub stworzenie czegoś wyjątkowego, aby porównać obiekty. Używanie czegokolwiek poza klasą do serializowania obiektu może spowodować dziwne zachowanie (w tym porównywanie obiektów różnych klas, które nigdy nie powinny prowadzić do równości).