2013-08-20 27 views
1

我有兩個多維數組,無論是這個樣子:如何正確使用array_udiff()?

Array 
(
    [0] => Array (
     'id' => 3, 
     'other' => 'some string', 
     'timestamp' => 2000-01-01 00:00:00 
    ), 

    [1] => Array (
     'id' => 6, 
     'other' => 'another string', 
     'timestamp' => 1835-01-01 00:00:00 
    ) 
) 

我試圖找到一種方法來找出哪些元素在一個陣列($b)顯示出來,而不是其他($a)以及是否有任何元素具有更改的值。如果$a是:

Array 
(
    [0] => Array (
     'id' => 3, 
     'other' => 'some string', 
     'timestamp' => 2000-01-01 00:00:00 
    ) 
) 

$b是:

Array 
(
    [0] => Array (
     'id' => 3, 
     'other' => 'some string', 
     'timestamp' => 2000-01-01 12:12:12 
    ), 

    [1] => Array (
     'id' => 4, 
     'other' => 'some string', 
     'timestamp' => 1900-01-01 01:12:23 
    ) 
) 

然後函數將返回:

Array 
(
    [0] => Array (
     'id' => 3, 
     'other' => 'some string', 
     'timestamp' => 2000-01-01 12:12:12 
    ), 

    [1] => Array (
     'id' => 4, 
     'other' => 'some string', 
     'timestamp' => 1900-01-01 01:12:23 
    ) 
) 

因爲id = 3元素已經改變(在timestamp場)和元素id = 4是新的,並且不會出現在其他數組中。我一直試圖做到這一點與array_udiff,但我仍然不知道它是如何工作的(它似乎首先排序兩個數組,但它是如何做比較?)。是array_udiff正確的方法,還是我應該寫一個自定義函數?

回答

0

您可以使用array_udiff並定義您自己的比較回調。我假設兩個數組的結構完全相同。

您可以定義自己的回調函數如下:

int comparison(Array $a, Array $b){ 
    if ($a['id']==$b['id'] && $a['other']==$b['other'] && $a['timestamp']==$b['timestamp']){ 
     return 0 
    }else{ 
     return -1 
    } 
} 

回調函數必須返回一個負整數,如果第一個參數小於第二;如果它更大,則爲正數;如果相等則爲0。然後,您可以將任何不同的數字返回爲0,以指示參數不同,如果它們相等,則返回0。

最後,你應該叫array_udiff如下:

array_udiff($a, $b, 'comparison') 

,你會得到哪些不是,或在$b不同的$a的元素列表。

請注意,如果您希望比較2個數組,那麼當其中一個元素比另一個元素多時,應該將第一個參數作爲第一個參數傳遞給新元素。

+0

回調函數不是必須返回所有的'0','1'和'-1'嗎? – n0pe

+0

@MaxMackie如果第一個參數分別小於,等於或大於第二個參數,則回調函數必須返回負數,0或正數。但是對於你的文檔,如果參數相等(返回0)或不同(返回正數或負數),則只需返回。 – Stratford

+0

但是如何處理/解釋-1,0和1? 1是包含,0和-1是否排除? – ahnbizcad

0

array_udiff函數「data_compare_func」的返回值是您定義的某個函數,但它必須返回小於,等於或大於零的整數,因此它可能不是您需要的正確函數。像這樣的自定義函數應該給你你需要的東西:

// this function loops through both arrays to find a match in the other array 
// it will skip entry comparisons when it goes through $arr2 because you already did it the first time 
function find_diff($arr1, $arr2) { 
    $ret = array(); 

    // we need to do two loops to find missing entries from both arrays 
    $ret = do_loop($arr1, $arr2, $ret, true); 
    $ret = do_loop($arr2, $arr1, $ret, false); 
    return $ret; 
} 

// this function does the looping though $arr1 to compare it to entries in $arr2 
// you can skip entry comparison if $compare_entries is false 
function do_loop($arr1, $arr2, $ret, $compare_entries = true) { 
    //look through all of $arr1 for same element in $arr2 based on $id 
    for ($i=0;$i<count($arr1);$i++) { 
     $id = $arr1[$i]['id']; 
     $found = false; 

     for ($j=0;$j<count($arr2);$j++) { 
      // id match found 
      if ($id == $arr2[$j]['id']) { 
       $found = true; 
       // only compare entries if you need to 
       if ($compare_entries) { 
        //check if other field is different 
        if (strcmp($arr1[$i]['other'],$arr2[$j]['other']) != 0) { 
         $ret = add_to_ret($arr1[$i], $ret); 
         break; 
        } 
        //check if timestamp field is different 
        if (strcmp($arr1[$i]['timestamp'],$arr2[$j]['timestamp']) != 0) { 
         $ret = add_to_ret($arr1[$i], $ret); 
         break; 
        } 
       } else { 
        break; 
       } 
      } 
     } 

     // entry from $arr1[$i] was not found in $arr2 
     if (!$found) { 
      $ret = add_to_ret($arr1[$i], $ret); 
     } 
    } 
    return $ret; 
} 


//this function only adds the new entry to $ret if it's ID isn't already in $ret 
function add_to_ret($entry, $ret) { 

    $id = $entry['id']; 

    for ($i=0;$i<count($ret);$i++) { 
     if ($id == $ret[$i]['id']) { 
      //skip adding, its already in there 
      return $ret; 
     } 
    } 
    //add it in 
    $ret[] = $entry; 
    return $ret; 
}