2012-08-28 10 views
7

Estoy usando usort para ordenar una matriz con una matriz asociativa dentro de cada elemento.PHP usort reordena matriz el valor de clasificación es el mismo para todos

Cuando todos los valores que estoy ordenando en la matriz son los mismos, sigue cambiando la posición de los elementos en la matriz, ¿hay alguna manera de evitar esto?

Por ejemplo esto:

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

puede ser cambiado a esto:

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

Esta es la función de clasificación:

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

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

He comprobado que la función weightSortImplementation es siempre regresando 0 mostrando que son lo mismo. Entonces, ¿por qué sigue reordenando la matriz?

+0

Eso es un problema interesante. Acabo de probar esto y, después de usar 'usort', el orden se invirtió. http://codepad.org/PRFpq8Ug –

+0

No deben estar usando un [stable sort] (http://en.wikipedia.org/wiki/Sorting_algorithm#Stability), que no garantiza el orden de los elementos si son igual. – JoeyJ

Respuesta

11

Aha, un caso para el Schwartzian Transform.

Básicamente consiste en tres pasos:

  1. decorar; usted convierte cada valor en una matriz con el valor como el primer elemento y la clave/índice como el segundo
  2. ordenar (como por normal)
  3. undecorate; se invierte el paso 1

Aquí se (me he ajustado a su caso en particular):

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'); 

El truco está en la siguiente afirmación:

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

Esto es lo que mantiene el orden correcto de tu matriz. Y no se requiere recursividad :)

+0

super stuff bro .. !! – mithunsatheesh

+0

Hmm parece que esto no funciona para mí en PHP 5.4. –

+0

@JensKohl ¿Tiene un script de prueba reproducible que podría ver? –

8

From the documentation:

Si dos miembros resultan ser iguales, su orden relativo en la matriz ordenada es indefinido.

Se puede utilizar esta función [source] que conserva el orden en el caso de dos elementos que son iguales:

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

¿Hay alguna forma de prevenir esto? Tal vez usando diferentes métodos de clasificación? o cambiando la implementación del género, supongo que podría obtener el tipo de peso para devolver 1 o -1 si son iguales? – Chris

+0

Creo que deberías atribuir tu fuente. Encontré este método duplicado [aquí] (http://stackoverflow.com/a/4353844/135101). –

Cuestiones relacionadas