2010-03-25 53 views
6

這將在Javascript(jQuery)中實現,但我認爲該方法可以用於任何語言。如何排序數組,但排除某些元素(要保留在陣列中的相同位置)

我有一個項目的數組,我需要執行排序。 但是數組中有一些項必須保持在相同的位置(相同的索引)。

有問題的數組是從<li>元素的列表構建的,我將附加到列表項的.data()值作爲要排序的值。

這裏最好的方法是什麼?

<ul id="fruit"> 
    <li class="stay">bananas</li> 
    <li>oranges</li> 
    <li>pears</li> 
    <li>apples</li> 
    <li class="stay">grapes</li> 
    <li>pineapples</li> 
</ul> 

<script type="text/javascript"> 
    var sugarcontent = new Array('32','21','11','45','8','99'); 
    $('#fruit li').each(function(i,e){ 
     $(this).data('sugar',sugarcontent[i]); 
    }) 
</script> 

我想結果如下排序列表...

<ul id="fruit"> 
     <li class="stay">bananas</li> <!-- score = 32 --> 
     <li>pineapples</li> <!-- score = 99 --> 
     <li>apples</li> <!-- score = 45 --> 
     <li>oranges</li> <!-- score = 21 --> 
     <li class="stay">grapes</li> <!-- score = 8 --> 
     <li>pears</li> <!-- score = 11 --> 
    </ul> 

謝謝!

回答

6

算法是:

  • 提取和排序沒有打上stay
  • 合併stay項目的項目和排序的項

    var sugarcontent = new Array(32, 21, 11, 45, 8, 99); 
    
    var items = $('#fruit li'); 
    
    items.each(function (i) { 
        $(this).data('sugar', sugarcontent[i]); 
        // Show sugar amount in each item text - for debugging purposes 
        if ($(this).hasClass('stay')) 
         $(this).text("s " + $(this).text()); 
        else 
         $(this).text(sugarcontent[i] + " " + $(this).text()); 
    }); 
    
    // Sort sortable items 
    var sorted = $(items).filter(':not(.stay)').sort(function (l, r) { 
        return $(l).data('sugar') - $(r).data('sugar'); 
    }); 
    
    // Merge stay items and sorted items 
    var result = []; 
    var sortedIndex = 0; 
    
    for (var i = 0; i < items.length; i++) 
        if (!$(items[i]).hasClass('stay')) { 
         result.push(sorted[sortedIndex]); 
         sortedIndex++; 
        } 
        else 
         result.push(items[i]); 
    
    // Show result 
    $('#fruit').append(result); 
    
+0

這是最類似於我最終結果的代碼,所以我標記爲正確 - 我確定由petersendidit提供的解決方案也很好(雖然它未經測試)。謝謝! – calumbrodie 2010-03-30 10:47:27

0

這將無法正常工作,貝文指出的那樣,但我會離開這裏的教育目的:

$('#fruit li').sort(function(a, b) { 
    return ($(a).hasClass('stay') || $(b).hasClass('stay')) 
     ? 0 : (a.data('sugar') > b.data('sugar') ? 1 : -1); 
}).appendTo('#fruit'); 

注意:您需要用「糖」作爲名稱參數設置糖數據:

.data('sugar', sugarcontent[i]); 
+3

這種方法的問題是固定的項目成爲此類障礙 - 任何低於固定點的物品將永遠不會超過它,反之亦然。 – Bevan 2010-03-25 20:51:40

+0

謝謝指出語法錯誤,我修正了上面的示例代碼。 – calumbrodie 2010-03-25 21:01:23

1

您認爲該解決方案是通用的並適用於任何開發環境是正確的。

您需要將元素列表劃分爲兩個不同的列表 - 要排序的元素和要排列的元素。然後,排序第一個列表並與第二個列表合併。你面對的關鍵問題是:大多數排序算法(包括QuickSort,這是大多數框架中最常見的算法),如果你的比較函數依賴於任何外部狀態(比如項目位置),它會變得非常不正常)。

+0

我應該使用jQuery合併函數還是連接數組和度假?如何確保我的數組「固定」項目在索引相同時優先考慮?你提出的解決方案正是我第一次嘗試這樣做的方式,但我無法完成工作。至少我知道我在正確的軌道上。感謝您的輸入! – calumbrodie 2010-03-25 20:55:52

+0

通過回答@Konstantin對我來說似乎很好(我的Javascript不能勝任任務+1) – Bevan 2010-03-26 06:24:32

3

這應做到:

var sugarcontent = new Array('32','21','11','45','8','99'); 
var list = $('#fruit'); 
var lis = list.find('li').each(function(i,e){ 
    $(this).data('score',sugarcontent[i]); 
}); 
var stay = lis.filter('.stay').each(function(){ 
    $(this).data('index',$(this).index()); 
}); 
lis.sort(function(a,b){ 
    return $(b).data('score') - $(a).data('score'); 
}).appendTo(list); 
stay.each(function(){ 
    var index = $(this).data('index'); 
    if (index == 0) { 
     list.prepend(this); 
    } else { 
     lis.filter(':eq('+index+')').insertAfter(this); 
    } 
} 

這緩存與類住宿項目的索引,然後它的排序分數,然後替換與類的物品留在後面在正確的位置。