2012-02-09 42 views
3

我有一個PHP usort()的問題。讓我們假設我有一個這樣的數組(這是一個簡化的,我還沒有與名稱的工作,我有對象的數組,不是數組):PHP usort不需要的行爲

$data = array(
    array('name' => 'Albert',  'last' => 'Einstein'), 
    array('name' => 'Lieserl',  'last' => 'Einstein'), 
    array('name' => 'Alan',  'last' => 'Turing' ), 
    array('name' => 'Mileva',  'last' => 'Einstein'), 
    array('name' => 'Hans Albert', 'last' => 'Einstein') 
); 

正如你所看到的,數組排序隨意。

現在,如果想通過last對它進行排序,我做的:

function sort_some_people($a, $b) { return strcmp($a['last'], $b['last']); } 
usort($data, 'sort_some_people'); 

而且我有:

Array (
    [0] => Array ([name] => Mileva  [last] => Einstein) 
    [3] => Array ([name] => Albert  [last] => Einstein) 
    [1] => Array ([name] => Lieserl  [last] => Einstein) 
    [2] => Array ([name] => Hans Albert [last] => Einstein) 
    [4] => Array ([name] => Alan   [last] => Turing ) 
) 

這是確定的,現在他們被last排序。但是,正如你所看到的,我已經完全失去了以前的排序。我在說什麼?我想保留它之前的數組排序,但是作爲排序的輔助。我希望我很清楚。 實際上我想使用usort()(所以,一個完全自定義的排序)的東西來排序數據,但如果排序字段是相同的兩個項目之間,我想保留他們的相對位置像以前一樣。考慮給出的例子,我想Lieserl Einstein出現在Mileva Einstein之前,因爲它在開始時就是這樣。

回答

2

PHP中使用的排序算法具有此屬性,如果項目匹配,則訂單未定義。

如果您需要保留訂單,那麼您必須推出自己的代碼。

好在有人已經擁有: http://www.php.net/manual/en/function.usort.php#38827

$data = array(
    array('name' => 'Albert',  'last' => 'Einstein'), 
    array('name' => 'Lieserl',  'last' => 'Einstein'), 
    array('name' => 'Alan',  'last' => 'Turing' ), 
    array('name' => 'Mileva',  'last' => 'Einstein'), 
    array('name' => 'Hans Albert', 'last' => 'Einstein') 
); 

function sort_some_people($a, $b) { 
     return strcmp($a['last'], $b['last']); 
} 

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

mergesort($data, 'sort_some_people'); 

print_r($data); 

輸出:

Array 
(
    [0] => Array 
     (
      [name] => Albert 
      [last] => Einstein 
     ) 

    [1] => Array 
     (
      [name] => Lieserl 
      [last] => Einstein 
     ) 

    [2] => Array 
     (
      [name] => Mileva 
      [last] => Einstein 
     ) 

    [3] => Array 
     (
      [name] => Hans Albert 
      [last] => Einstein 
     ) 

    [4] => Array 
     (
      [name] => Alan 
      [last] => Turing 
     ) 

) 

瞧!

+0

接受。無論如何,我以更簡潔的方式解決。在'usort()'之前,我將原始數組位置(索引)存儲在每個對象中(即'$ data [$ i] - > original_index = $ i'),然後在比較函數中檢查此值,返回'0'(即相同的排序值)。很簡單,聰明,不是嗎? :) 謝謝你們! – 2012-02-09 20:55:38

1
$compare = strcmp($a['last'], $b['last']); 
if ($compare == 0) 
    $compare = strcmp($a['name'], $b['name']); 
return $compare 
+0

查看評論我留在蒂姆庫珀的答案。 – 2012-02-09 14:35:16

+0

您可以舉一個你想要的結果的例子,而不是你得到的結果 – 2012-02-09 14:40:31

+0

查看更新的問題。我的錯:) – 2012-02-09 14:42:08

0

試試這個:

function sort_some_people($a, $b) 
{ 
    $compareValue = 10 * strcmp($a['last'], $b['last']); 
    $compareValue += 1 * strcmp($a['name'], $b['name']); 
    return $compareValue; 
} 

樣品:http://codepad.org/zkHviVBM

此功能使用十進制系統的每個數字的排序標準。先來的那個有最高的數字。可能不是最聰明的,但爲我工作。

+0

和Mark Ba​​ker和Tim Cooper一樣。對不起,我用蠕蟲的方式問了問題。我現在更新了它。 – 2012-02-09 14:43:00

1

您正在尋找一個stable sorting algorithm,哪個php不提供。請注意,即使它有時可能看起來很穩定,也不能保證它,並且在給定某些輸入時很可能會行爲不端。

如果您知道其他列的排序標準,則可以一次將其全部採用以獲得所需的行爲。 array_multisort這樣做。以下是比較強大的方式,因爲比較邏輯完全由用戶定義。

// should behave similar to sql "order by last, first" 
$comparatorSequence = array(
    function($a, $b) { 
     return strcmp($a['last'], $b['last']); 
    } 
    , function($a, $b) { 
     return strcmp($a['first'], $b['first']); 
    } 
    // more functions as needed 
); 

usort($theArray, function($a, $b) use ($comparatorSequence) { 
    foreach ($comparatorSequence as $cmpFn) { 
     $diff = call_user_func($cmpFn, $a, $b); 
     if ($diff !== 0) { 
      return $diff; 
     } 
    } 
    return 0; 
}); 

如果你真的需要一個穩定的排序,因爲元素的現存秩序的心不是很好定義,嘗試寫自己的排序。例如bubble sort很容易編寫。只要列表中元素的數量相對較少,這是一個很好的解決方案,否則就要實現其他穩定排序算法之一。

+0

不幸的是我不知道原來的排序標準(沒有)。我不知道對於排序算法有一個精確的定義,其行爲如我所述。我看到冒泡排序和合並排序(我最清楚的排序)是穩定的排序...所以... * [OT] * PHP在內部使用什麼算法?!? – 2012-02-09 15:38:36

+0

php使用一個版本的quicksort – goat 2012-02-09 15:42:59

+0

看看zaf的答案。 – goat 2012-02-09 15:43:30