在PHP 中, usort()函數用於對數組進行自定義排序。它非常強大,可以根據用戶定義的比較函數來對數組元素進行排序。但在實際使用過程中,我們可能會遇到一些排序錯誤,這些問題通常與比較函數的返回值不正確或排序的數組結構有關。本文將分析一些常見的錯誤並給出相應的解決方法。
usort()函數的核心是一個用戶定義的比較函數。該比較函數接受兩個參數,表示數組中的兩個元素。比較函數應返回一個整數,表示這兩個元素的順序:
返回值小於0:表示第一個元素應該排在第二個元素前面。
返回值等於0:表示兩個元素相等,它們的相對順序不變。
返回值大於0:表示第一個元素應該排在第二個元素後面。
如果你的比較函數沒有遵循這個規則, usort()就會出現排序錯誤。常見的錯誤是比較函數返回值的類型不對,或者返回值範圍不符合要求。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span> < </span><span><span class="hljs-variable">$b</span></span><span>) </span><span><span class="hljs-keyword">return</span></span><span> -</span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span> > </span><span><span class="hljs-variable">$b</span></span><span>) </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-string">'equal'</span></span><span>; </span><span><span class="hljs-comment">// 錯誤的返回值</span></span><span>
});
</span></span>
在上面的示例中, 'equal'是一個字符串,而usort()期望返回一個整數。這樣會導致排序行為不符合預期。
確保比較函數始終返回整數值。正確的做法是返回-1 、 0或1 。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span> < </span><span><span class="hljs-variable">$b</span></span><span>) </span><span><span class="hljs-keyword">return</span></span><span> -</span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$a</span></span><span> > </span><span><span class="hljs-variable">$b</span></span><span>) </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-number">1</span></span><span>;
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-number">0</span></span><span>; </span><span><span class="hljs-comment">// 正確的返回值</span></span><span>
});
</span></span>
usort()函數適用於各種類型的數組元素,但如果數組中的元素類型不一致,排序結果可能會不可預測。比如,混合了數字和字符串的數組在排序時可能會導致錯誤的順序。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-string">'1'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$a</span></span><span> - </span><span><span class="hljs-variable">$b</span></span><span>;
});
</span></span>
儘管usort()會嘗試轉換數組元素的類型,但如果比較操作中涉及了字符串與數字的混合,可能會導致意料之外的結果。
在比較函數中,顯式地轉換數組元素的類型,以確保比較邏輯的一致性。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-string">'1'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> (</span><span><span class="hljs-keyword">int</span></span><span>)</span><span><span class="hljs-variable">$a</span></span><span> - (</span><span><span class="hljs-keyword">int</span></span><span>)</span><span><span class="hljs-variable">$b</span></span><span>; </span><span><span class="hljs-comment">// 強制轉換為整數</span></span><span>
});
</span></span>
當你使用usort()對多維數組進行排序時,可能會遇到數組元素嵌套結構導致排序無法正確進行的問題。特別是當你需要按某個子元素來排序時,如果比較函數沒有正確地訪問子元素,排序可能會失敗。
<span><span><span class="hljs-variable">$array</span></span><span> = [
[</span><span><span class="hljs-string">'id'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-string">'name'</span></span><span> => </span><span><span class="hljs-string">'Tom'</span></span><span>],
[</span><span><span class="hljs-string">'id'</span></span><span> => </span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-string">'name'</span></span><span> => </span><span><span class="hljs-string">'Jerry'</span></span><span>],
[</span><span><span class="hljs-string">'id'</span></span><span> => </span><span><span class="hljs-number">2</span></span><span>, </span><span><span class="hljs-string">'name'</span></span><span> => </span><span><span class="hljs-string">'Alice'</span></span><span>]
];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'id'</span></span><span>] - </span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'id'</span></span><span>];
});
</span></span>
在這個例子中,代碼看起來沒有問題,但如果數組的結構發生了變化,例如'id'鍵不存在或其值為空,就可能導致排序錯誤。
確保比較函數處理所有可能的情況,例如通過檢查鍵是否存在,或者通過提供默認值來防止錯誤。
<span><span><span class="hljs-variable">$array</span></span><span> = [
[</span><span><span class="hljs-string">'id'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-string">'name'</span></span><span> => </span><span><span class="hljs-string">'Tom'</span></span><span>],
[</span><span><span class="hljs-string">'id'</span></span><span> => </span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-string">'name'</span></span><span> => </span><span><span class="hljs-string">'Jerry'</span></span><span>],
[</span><span><span class="hljs-string">'id'</span></span><span> => </span><span><span class="hljs-number">2</span></span><span>, </span><span><span class="hljs-string">'name'</span></span><span> => </span><span><span class="hljs-string">'Alice'</span></span><span>]
];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> (</span><span><span class="hljs-keyword">isset</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'id'</span></span><span>]) ? </span><span><span class="hljs-variable">$a</span></span><span>[</span><span><span class="hljs-string">'id'</span></span><span>] : </span><span><span class="hljs-number">0</span></span><span>) - (</span><span><span class="hljs-keyword">isset</span></span><span>(</span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'id'</span></span><span>]) ? </span><span><span class="hljs-variable">$b</span></span><span>[</span><span><span class="hljs-string">'id'</span></span><span>] : </span><span><span class="hljs-number">0</span></span><span>);
});
</span></span>
usort()對數組進行排序時,會重新索引數組,這意味著原來的數組索引將被丟棄。如果你需要保持原數組的鍵, usort()可能不適合你。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">3</span></span><span> => </span><span><span class="hljs-string">'apple'</span></span><span>, </span><span><span class="hljs-number">1</span></span><span> => </span><span><span class="hljs-string">'banana'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span> => </span><span><span class="hljs-string">'cherry'</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">strcmp</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>);
});
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>
上述代碼將輸出沒有原始索引的數組:
<span><span><span class="hljs-title function_ invoke__">Array</span></span><span>
(
[</span><span><span class="hljs-number">0</span></span><span>] => apple
[</span><span><span class="hljs-number">1</span></span><span>] => banana
[</span><span><span class="hljs-number">2</span></span><span>] => cherry
)
</span></span>
如果你需要保留原數組的鍵,可以使用uasort() ,它與usort()的區別是會保持原數組的鍵。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">3</span></span><span> => </span><span><span class="hljs-string">'apple'</span></span><span>, </span><span><span class="hljs-number">1</span></span><span> => </span><span><span class="hljs-string">'banana'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span> => </span><span><span class="hljs-string">'cherry'</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">uasort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">strcmp</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>);
});
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>
這樣就能保留原始的鍵順序:
<span><span><span class="hljs-title function_ invoke__">Array</span></span><span>
(
[</span><span><span class="hljs-number">3</span></span><span>] => apple
[</span><span><span class="hljs-number">1</span></span><span>] => banana
[</span><span><span class="hljs-number">2</span></span><span>] => cherry
)
</span></span>
在對包含浮動小數的數組進行排序時,由於浮動點數的精度限制,可能會導致排序錯誤。尤其是當數字的精度非常高時,比較可能不如預期。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">1.0000001</span></span><span>, </span><span><span class="hljs-number">1.0000002</span></span><span>, </span><span><span class="hljs-number">1.0000003</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$a</span></span><span> - </span><span><span class="hljs-variable">$b</span></span><span>;
});
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>
浮動數的比較可能會受到精度影響,導致排序結果出現不穩定。
使用round()函數限制浮動小數的位數,以避免由於浮動精度問題引發的排序錯誤。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">1.0000001</span></span><span>, </span><span><span class="hljs-number">1.0000002</span></span><span>, </span><span><span class="hljs-number">1.0000003</span></span><span>];
</span><span><span class="hljs-title function_ invoke__">usort</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">round</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-number">7</span></span><span>) - </span><span><span class="hljs-title function_ invoke__">round</span></span><span>(</span><span><span class="hljs-variable">$b</span></span><span>, </span><span><span class="hljs-number">7</span></span><span>); </span><span><span class="hljs-comment">// 限制精度</span></span><span>
});
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>