PHPでは、 USORT()関数を使用して、配列のソートをカスタマイズします。これは非常に強力であり、ユーザー定義の比較関数に基づいて配列要素をソートできます。しかし、実際に使用すると、通常、比較関数またはソートされた配列構造の誤った返品値に関連するいくつかのソートエラーが発生する場合があります。この記事では、いくつかの一般的なエラーを分析し、対応するソリューションを提供します。
USORT()関数のコアは、ユーザー定義の比較関数です。この比較関数は、配列内の2つの要素を表す2つのパラメーターを受け入れます。比較関数は、これら2つの要素の順序を表す整数を返す必要があります。
戻り値は0未満です。つまり、最初の要素が2番目の要素よりも先にあることを意味します。
戻り値は0に等しくなります。つまり、2つの要素が等しく、相対順序が変更されないことを意味します。
0を超える返品値:最初の要素の後に2番目の要素が続くことを意味します。
比較関数がこのルールに従わない場合、 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>