PHP usort reorders array значение сортировки одинаково для всех

Я использую 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, показывая, что они одинаковы. Итак, почему это все еще переупорядочивает массив?

Ага, случай Шварцского преобразования .

Он состоит в основном из трех шагов:

  1. украшения; вы превращаете каждое значение в массив со значением как первым элементом, а ключ / индекс – вторым
  2. сортировать (как обычно)
  3. undecorate; вы меняете шаг 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) 

Это то, что поддерживает правильный порядок вашего массива. И, рекурсии не требуется 🙂

Из документации :

Если два члена сравниваются как равные, их относительный порядок в отсортированном массиве не определен.

Вы можете использовать эту функцию [источник], которая сохраняет порядок в случае, когда два элемента равны:

 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; }