2015-10-02 40 views
4

我正在做以下操作,從樹視圖獲取特定節點,然後從這些節點獲取文本,過濾文本以刪除唯一值,然後將自定義圖像附加到重複節點。對於這個我不得不循環4次。是否有一個更簡單的方法來做到這一點?我擔心這是大量數據的表現。Loop,獲取唯一值並更新

//Append duplicate item nodes with custom icon 
function addRemoveForDuplicateItems() { 
    var treeView = $('#MyTree').data('t-TreeView li.t-item'); 
    var myNodes = $("span.my-node", treeView); 
    var myNames = []; 

    $(myNodes).each(function() { 
     myNames.push($(this).text()); 
    }); 

    var duplicateItems = getDuplicateItems(myNames); 

    $(myNodes).each(function() { 
     if (duplicateItems.indexOf($(this).text()) > -1) { 
      $(this).parent().append(("<span class='remove'></span>")); 
     } 
    }); 
} 

//Get all duplicate items removing unique ones 
//Input [1,2,3,3,2,2,4,5,6,7,7,7,7] output [2,3,3,2,2,7,7,7,7] 
function getDuplicateItems(myNames) { 
    var duplicateItems = [], itemOccurance = {}; 

    for (var i = 0; i < myNames.length; i++) { 
     var dept = myNames[i]; 
     itemOccurance[dept] = itemOccurance[dept] >= 1 ? itemOccurance[dept] + 1 : 1; 
    } 
    for (var item in itemOccurance) { 
     if (itemOccurance[item] > 1) 
      duplicateItems.push(item); 
    } 
    return duplicateItems; 
} 

回答

0

如果我理解正確的話,這裏的整點只是爲了標記重複,對吧?你應該能夠做到這兩個簡單的傳球:如果你是真正關心性能

var seen = {}; 
var SEEN_ONCE = 1; 
var SEEN_DUPE = 2; 

// First pass, build object 
myNodes.each(function() { 
    var name = $(this).text(); 
    var seen = seen[name]; 
    seen[name] = seen ? SEEN_DUPE : SEEN_ONCE; 
}); 

// Second pass, append node 
myNodes.each(function() { 
    var name = $(this).text(); 
    if (seen[name] === SEEN_DUPE) { 
     $(this).parent().append("<span class='remove'></span>"); 
    } 
}); 

,注意循環訪問DOM元素比遍歷一個內存陣列更是一個性能問題的。調用$(myNodes).each(...)的調用可能會比迭代超過相同長度的可比較陣列要貴得多。您可以通過在陣列上運行第二遍並僅在必要時訪問DOM節點來獲得一些效率:

var names = []; 
var seen = {}; 
var SEEN_ONCE = 1; 
var SEEN_DUPE = 2; 

// First pass, build object 
myNodes.each(function() { 
    var name = $(this).text(); 
    var seen = seen[name]; 
    names.push(name); 
    seen[name] = seen ? SEEN_DUPE : SEEN_ONCE; 
}); 

// Second pass, append node only for dupes 
names.forEach(function(name, index) { 
    if (seen[name] === SEEN_DUPE) { 
     myNodes.eq(index).parent() 
      .append("<span class='remove'></span>"); 
    } 
}); 
0

此代碼的方法是通過列表,使用屬性名稱來指示值是否在數組中。執行後,itemOccurance將包含所有名稱的列表,不會有重複項。

var i, dept, itemOccurance = {}; 
for (i = 0; i < myNames.length; i++) { 
    dept = myNames[i]; 
    if (typeof itemOccurance[dept] == undefined) { 
     itemOccurance[dept] = true; 
    } 
} 
0

如果你必須保持getDuplicateItems()作爲一個獨立的,通用的功能,那麼第一個循環(從myNodesmyNames)和最後一個循環(循環再次向myNodes添加span)將是不可避免的。但我很好奇。根據你的代碼,duplicateItems只能是一套!這有助於簡化getDuplicateItems()內的2個循環。 @ user2182349的回答只需要一個修改:添加return,例如return Object.keys(itemOccurance)

0

如果你只關注查明重複,不會特別在意發生的確切數字,那麼你可以考慮重構你的getDuplicateItems()功能,像這樣:

function getDuplicateItems(myNames) { 
    var duplicateItems = [], clonedArray = myNames.concat(), i, dept; 
    for(i=0;i<clonedArray.length;i+=1){ 
     dept = clonedArray[i]; 
     if(clonedArray.indexOf(dept) !== clonedArray.lastIndexOf(dept)){    
      if(duplicateItems.indexOf(dept) === -1){ 
       duplicateItems.push(dept); 
      } 
      /* Remove duplicate found by lastIndexOf, since we've already established that it's a duplicate */ 
      clonedArray.splice(clonedArray.lastIndexOf(dept), 1); 
     } 
    } 
    return duplicateItems; 
}