У меня есть два многомерных массива, которые выглядят примерно так:
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
правильным методом или я должен написать пользовательскую функцию?
Вы можете использовать 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')
И вы получите список элементов $a
которые не являются или отличаются в $b
.
Обратите внимание: если вы хотите сравнить массив 2, когда один из них имеет больше элементов, чем другой, вы должны передать в качестве первого аргумента массив с новыми элементами.
Возврат для функции 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; }