2012-08-28 31 views
7

Tôi đang sử dụng usort để sắp xếp mảng có mảng liên kết trong mỗi phần tử.PHP usort reorders mảng giá trị sắp xếp giống nhau cho tất cả

Khi tất cả các giá trị tôi sắp xếp trong mảng đều giống nhau thì nó vẫn thay đổi vị trí của các phần tử trong mảng, có cách nào để ngăn chặn điều này không?

Ví dụ này:

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

Có thể được thay đổi như sau:

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

Đây là chức năng sắp xếp:

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

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

Tôi đã kiểm tra rằng weightSortImplementation chức năng luôn luôn là trở về 0 cho thấy chúng giống nhau. Vậy tại sao điều này vẫn sắp xếp lại mảng?

+0

Đó là một vấn đề thú vị. Tôi vừa kiểm tra điều này, và sau khi sử dụng 'usort' lệnh đã được đảo ngược. http://codepad.org/PRFpq8Ug –

+0

Chúng không được sử dụng [loại ổn định] (http://en.wikipedia.org/wiki/Sorting_algorithm#Stability), không đảm bảo thứ tự các phần tử nếu chúng là công bằng. – JoeyJ

Trả lời

11

Aha, một trường hợp cho Schwartzian Transform.

Nó về cơ bản bao gồm ba bước sau:

  1. decorate; bạn biến mọi giá trị thành một mảng có giá trị là phần tử đầu tiên và khóa/chỉ mục là thứ hai
  2. sắp xếp (theo bình thường)
  3. undecorate; bạn đảo ngược bước 1

Ở đây nó được (Tôi đã điều chỉnh nó để trường hợp sử dụng cụ thể của bạn):

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

Bí quyết là ở sự khẳng định sau đây:

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

Đây là những gì giữ đúng thứ tự của mảng của bạn. Và, không cần đệ quy :)

+0

siêu thứ bro .. !! – mithunsatheesh

+0

Hmm có vẻ như điều này không hoạt động đối với tôi trên PHP 5.4. –

+0

@JensKohl Bạn có kịch bản kiểm tra có thể tái sản xuất được không? –

8

From the documentation:

Nếu hai thành viên so sánh như bình đẳng, trật tự tương đối của chúng trong mảng được sắp xếp là undefined.

Bạn có thể sử dụng chức năng này [source] riêng giữ gìn trật tự trong trường hợp của hai yếu tố là như nhau:

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

Có cách nào để ngăn chặn điều này không? Có thể sử dụng các phương pháp phân loại khác nhau? hoặc thay đổi cách sắp xếp sắp xếp, tôi giả sử tôi có thể lấy trọng số sắp xếp để trả về 1 hoặc -1 nếu chúng giống nhau không? – Chris

+0

Tôi nghĩ bạn nên phân bổ nguồn của mình. Tôi tìm thấy phương pháp này nhân đôi [ở đây] (http://stackoverflow.com/a/4353844/135101). –

Các vấn đề liên quan