最近遇到使用 PHP 函式庫的 array_uintersect() ,去找出兩陣列有相同的元素,不過執行結果不如預期。目前仍未找到解法,希望藉寫下紀錄,提醒自己以後找到解法再回來補上。array_uintersect() PHP官方使用文件請看此。
目標:比對兩陣列內的資料,找出相同的資料元素。
格式說明:例如 $array1
, $array2
是陣列的變數,$array1
內的陣列元素格式是另一個陣列 $ary3
,$array1
裡有很多個 $ary3
,每個 $ary3
格式有六欄,$ary3[0]
型態是 string,$ary3[1]
是 string,$ary3[2]
是 string,$ary3[3]
是 float(小數點後5位四捨五入),$ary3[4]
是 string,$ary3[5]
是 string。
$array2
跟 $array1
類似,不過 $array2
有七欄,$array2
內的陣列元素格式是另一個陣列 $ary4
,$array2
裡有很多個 $ary4
,每個 $ary4
格式有七欄,$ary4[0]
到 $ary4[6]
型態都是 string。比較貼切的比喻是你可以想像每個 $ary3
和 $ary4
是資料庫概念中資料表內的一筆資料。
使用情境說明:
主要使用
$commonElements = array_uintersect( $array1, $array2, "my_exec_comparison" );
預計 $commonElements
主要存放由 array_uintersect()
回傳的相同資料元素陣列,但未如得到預期結果。 array_uintersect()
函式會以 $array1
為主,用撰寫者自定義的比較函式 (如上例是 my_exec_comparison
) ,去尋找 $array1
和 $array2
兩陣列之間共同的值。
嘗試過的 my_exec_comparison
撰寫方法,但未解決:
function my_exec_comparison ( $a, $b) {
if( $a[0] == $b[0] && $a[1] == $b[1] && $a[2] == $b[2] && $a[3] == $b[3] && $a[4] == $b[4] && $a[5] == $b[5] ){
return 0;
} else if ( $a[0] > $b[0] || $a[1] > $b[1] || $a[2] > $b[2] || $a[3] > $b[3] || $a[4] > $b[4] || $a[5] > $b[5] ) {
return 1;
} else {
return -1;
}
}
function my_exec_comparison ( $a, $b) {
if( $a[0] === $b[0] && $a[1] === $b[1] && $a[2] === $b[2] && $a[3] === $b[3] && $a[4] === $b[4] && $a[5] === $b[5] ){
return 0;
} else if ( $a[0] > $b[0] || $a[1] > $b[1] || $a[2] > $b[2] || $a[3] > $b[3] || $a[4] > $b[4] || $a[5] > $b[5] ) {
return 1;
} else {
return -1;
}
}
strcmp
function my_exec_comparison ( $a, $b) {
if( 0 == strcmp( $a[0], $b[0] ) && 0 == strcmp( $a[1], $b[1] ) && 0 == strcmp( $a[2], $b[2] ) && 0 == strcmp( $a[3], $b[3] ) && 0 == strcmp( $a[4], $b[4] ) && 0 == strcmp( $a[5] , $b[5] ) ){
return 0;
} else if ( strcmp( $a[0] , $b[0] ) > 0 || strcmp( $a[1] , $b[1] ) > 0 || strcmp( $a[2] , $b[2] ) > 0 || strcmp( $a[3] , $b[3] ) > 0 || strcmp( $a[4] , $b[4] ) > 0 || strcmp( $a[5] , $b[5] ) > 0 ) {
return 1;
} else {
return -1;
}
}
strcmp
and strval
function my_exec_comparison ( $a, $b) {
if( 0 == strcmp( $a[0], $b[0] ) && 0 == strcmp( $a[1], $b[1] ) && 0 == strcmp( $a[2], $b[2] ) && 0 == strcmp( strval( $a[3] ), strval( $b[3] ) ) && 0 == strcmp( $a[4], $b[4] ) && 0 == strcmp( $a[5] , $b[5] ) ){
return 0;
} else if ( strcmp( $a[0] , $b[0] ) > 0 || strcmp( $a[1] , $b[1] ) > 0 || strcmp( $a[2] , $b[2] ) > 0 || strcmp( strval( $a[3] ) , strval( $b[3] ) ) > 0 || strcmp( $a[4] , $b[4] ) > 0 || strcmp( $a[5] , $b[5] ) > 0 ) {
return 1;
} else {
return -1;
}
}
strcasecmp
function my_exec_comparison ( $a, $b) {
if( 0 == strcasecmp( $a[0], $b[0] ) && 0 == strcasecmp( $a[1], $b[1] ) && 0 == strcasecmp( $a[2], $b[2] ) && 0 == strcasecmp( $a[3], $b[3] ) && 0 == strcasecmp( $a[4], $b[4] ) && 0 == strcasecmp( $a[5] , $b[5] ) ){
return 0;
} else if ( strcasecmp( $a[0] , $b[0] ) > 0 || strcasecmp( $a[1] , $b[1] ) > 0 || strcasecmp( $a[2] , $b[2] ) > 0 || strcasecmp( $a[3] , $b[3] ) > 0 || strcasecmp( $a[4] , $b[4] ) > 0 || strcasecmp( $a[5] , $b[5] ) > 0 ) {
return 1;
} else {
return -1;
}
}
strcasecmp
and strval
function my_exec_comparison ( $a, $b) {
if( 0 == strcasecmp( $a[0], $b[0] ) && 0 == strcasecmp( $a[1], $b[1] ) && 0 == strcasecmp( $a[2], $b[2] ) && 0 == strcasecmp( strval( $a[3] ), strval( $b[3] ) ) && 0 == strcasecmp( $a[4], $b[4] ) && 0 == strcasecmp( $a[5] , $b[5] ) ){
return 0;
} else if ( strcasecmp( $a[0] , $b[0] ) > 0 || strcasecmp( $a[1] , $b[1] ) > 0 || strcasecmp( $a[2] , $b[2] ) > 0 || strcasecmp( strval( $a[3] ) , strval( $b[3] ) ) > 0 || strcasecmp( $a[4] , $b[4] ) > 0 || strcasecmp( $a[5] , $b[5] ) > 0 ) {
return 1;
} else {
return -1;
}
}
20170131 更新:感謝 carlcarl 提供符合這情境的正確用法
function carlcarl_test_uintersect_3($a, $b){
$result = 0;
for ($i = 0; $i < 6; $i++) {
if ($i === 3) {
$result = strcmp(trim(strval(floatval($a[$i])), '0'), trim(strval(floatval($b[$i])), '0'));
} else {
$result = strcmp(trim(strval($a[$i]), '0'), trim(strval($b[$i]), '0'));
}
if ($result !== 0) return $result;
}
return $result;
}
依據跟他詢問的 PHP 轉換變數型態問題,我改寫上述第四個函式:
解決方法:特定欄位不論它是文字或是浮點數,都先轉換成浮點數,再轉換成文字,以保證其型態。
function my_test_uintersect_4($a, $b){
//strcmp and strval, floatval
if( 0 == strcmp( $a[0], $b[0] ) && 0 == strcmp( $a[1], $b[1] ) && 0 == strcmp( $a[2], $b[2] ) && 0 == strcmp( strval( floatval($a[3]) ), strval( floatval( $b[3] ) ) ) && 0 == strcmp( $a[4], $b[4] ) && 0 == strcmp( $a[5] , $b[5] ) ){
return 0;
} else if ( strcmp( $a[0] , $b[0] ) > 0 || strcmp( $a[1] , $b[1] ) > 0 || strcmp( $a[2] , $b[2] ) > 0 || strcmp( strval( floatval( $a[3] ) ) , strval( floatval( $b[3] ) ) ) > 0 || strcmp( $a[4] , $b[4] ) > 0 || strcmp( $a[5] , $b[5] ) > 0 ) {
return 1;
} else {
return -1;
}
}
因為是製作測資時正在看 KKBOX 音樂風雲榜的電視直播,以此為靈感製作測資的欄位,實際內容與 KKBOX 公司無關。每欄位的欄位型態如本文起頭所述,測資與程式碼如下:
$array1 = array();
$array2 = array();
//id, name, song, 熱門倍率, 地點, 播放裝置
$ary3 = array("1", "科科", "就是有鬆", 10.94530, "台中市", "MobilePhone"); // common
array_push($array1, $ary3);
$ary3 = array("2", "盒子", "不為誰而做的歌", 15.33333, "台灣", "AllDevice"); // different
array_push($array1, $ary3);
$ary3 = array("3", "電速", "泡沫", 9.24601, "香港", "Web"); // common
array_push($array1, $ary3);
$ary3 = array("4", "兄弟本色", "Fly out", 10.00000, "台北市", "iTune"); // different
array_push($array1, $ary3);
$ary4 = array("1", "科科", "就是有鬆", "10.94530", "台中市", "MobilePhone", "1"); // common
$ary4 = array("2", "盒子", "不為誰而做的歌", "7.00032", "台灣", "AllDevice", "2"); //different at number
array_push($array2, $ary4);
$ary4 = array("3", "電速", "泡沫", "9.24601", "香港", "Web", "0"); // common
array_push($array2, $ary4);
$ary4 = array("4", "兄弟本色", "Come Home", "7.59600", "英國", "spotify PS4 app","1"); // different at song, number, location and device
array_push($array2, $ary4);
$ary4 = array("5", "鼓鼓", "可以唷", "8.01306", "台中市", "MobilePhone", "0");// different at id, name, song, number, location, device. totally new.
array_push($array2, $ary4);
echo "======n";
$result3 = array_uintersect($array1, $array2, "my_test_uintersect_3");
//echo "result3: " . var_dump($result3);
var_dump($result3);
$carlcarlResult = array_uintersect($array1, $array2, "carlcarl_test_uintersect_3" );
var_dump($carlcarlResult);
$result4 = array_uintersect($array1, $array2, "my_test_uintersect_4");
var_dump($result4);
正確的執行結果如下:
array(2) {
[0]=>
array(6) {
[0]=>
string(1) "1"
[1]=>
string(6) "科科"
[2]=>
string(12) "就是有鬆"
[3]=>
float(10.9453)
[4]=>
string(9) "台中市"
[5]=>
string(11) "MobilePhone"
}
[2]=>
array(6) {
[0]=>
string(1) "3"
[1]=>
string(6) "電速"
[2]=>
string(6) "泡沫"
[3]=>
float(9.24601)
[4]=>
string(6) "香港"
[5]=>
string(3) "Web"
}
}