7

私はusortを使用して、各要素内の連想配列で配列を並べ替えています。

配列内で並べ替えているすべての値が同じ場合でも、配列内の要素の位置が変更されますが、これを防ぐ方法はありますか?

例:これ:

array(
    array('name' => 'Ben', 'authn_weight' => 85.3),
    array('name' => 'Josh', 'authn_weight' => 85.3),
    array('name' => 'Fred', 'authn_weight' => 85.3)
);

これに変更される可能性があります:

array(
    array('name' => 'Josh', 'authn_weight' => 85.3),
    array('name' => 'Ben', 'authn_weight' => 85.3),
    array('name' => 'Fred', 'authn_weight' => 85.3)
);

これはソート関数です:

private function weightSortImplementation($a, $b){ 
    $aWeight = $a['autn_weight'];
    $bWeight = $b['autn_weight'];

    if ($aWeight == $bWeight) {
        return 0;
    }
    return ($aWeight < $bWeight) ? 1 : -1;
}

weightSortImplementation関数が常に0を返し、同じであることを示していることを確認しました。では、なぜこれがまだ配列を並べ替えているのですか?

4

2 に答える 2

13

ああ、シュワルツ変換の場合。

基本的に3つのステップで構成されています。

  1. 飾る; すべての値を、値を最初の要素、キー/インデックスを2番目の要素として配列に変換します
  2. 並べ替え(通常どおり)
  3. 飾り気のない; ステップ1を逆にします

ここにあります(私はあなたの特定のユースケースにそれを微調整しました):

function decorate(&$v, $k)
{
    $v['authn_weight'] = array($v['authn_weight'], $k);
}

function undecorate(&$v, $k)
{
    $v['authn_weight'] = $v['authn_weight'][0];
}

array_walk($a, 'decorate');
usort($a, 'weightSortImplementation');
array_walk($a, 'undecorate');

秘訣は次のアサーションにあります。

array($x, 0) < array($x, 1)

これは、配列の正しい順序を維持するものです。そして、再帰は必要ありません:)

于 2012-08-28T16:52:57.593 に答える
9

ドキュメントから

2つのメンバーが等しいと比較した場合、ソートされた配列での相対的な順序は定義されていません。

2つの要素が等しい場合に順序を保持するこの関数[ソース]を使用できます。

function mergesort(&$array, $cmp_function = 'strcmp') {
    // Arrays of size < 2 require no action.
    if (count($array) < 2) return;
    // Split the array in half
    $halfway = count($array) / 2;
    $array1 = array_slice($array, 0, $halfway);
    $array2 = array_slice($array, $halfway);
    // Recurse to sort the two halves
    mergesort($array1, $cmp_function);
    mergesort($array2, $cmp_function);
    // If all of $array1 is <= all of $array2, just append them.
    if (call_user_func($cmp_function, end($array1), $array2[0]) < 1) {
        $array = array_merge($array1, $array2);
        return;
    }
    // Merge the two sorted arrays into a single sorted array
    $array = array();
    $ptr1 = $ptr2 = 0;
    while ($ptr1 < count($array1) && $ptr2 < count($array2)) {
        if (call_user_func($cmp_function, $array1[$ptr1], $array2[$ptr2]) < 1) {
            $array[] = $array1[$ptr1++];
        }
        else {
            $array[] = $array2[$ptr2++];
        }
    }
    // Merge the remainder
    while ($ptr1 < count($array1)) $array[] = $array1[$ptr1++];
    while ($ptr2 < count($array2)) $array[] = $array2[$ptr2++];
    return;
} 
于 2012-08-28T16:25:21.590 に答える