2013-08-20 86 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; 
}