循环,获取唯一值并更新

时间:2015-10-02 00:52:04

标签: javascript jquery performance

我正在执行以下操作,从树视图中获取某些节点,然后从这些节点获取文本,过滤文本以删除唯一,然后将自定义图像附加到重复节点。

为此,我必须循环4次。有一种更简单的方法吗?我担心它对大量数据的性能。

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

4 个答案:

答案 0 :(得分:0)

此代码的方法是遍历列表,使用属性名称来指示值是否在数组中。执行后,itemOccurance将包含所有名称的列表,没有重复项。

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

答案 1 :(得分:0)

如果您必须将getDuplicateItems()作为单独的通用函数,那么第一个循环(从myNodesmyNames)和最后一个循环(再次迭代myNodes来添加span)是不可避免的。但我很好奇。根据您的代码,duplicateItems可以只是一组!这有助于简化getDuplicateItems()内的2个循环。 @ user2182349的答案只需要一次修改:添加return,例如return Object.keys(itemOccurance)

答案 2 :(得分: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;
}

答案 3 :(得分: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>");
    }
});