查找具有相同属性值的元素的最快方法

3
我将解析一些带有URL为ID的div,如果相同的url/ID存在,则我想要绕过它。因此,在每次添加时,我都需要搜索数百个div以查找所有这些div具有的属性相同的值。
示例:
HTML:
<div data-id="http://stackoverflow.com"></div>
<div data-id="http://engadget.com"></div>
<div data-id="http://9gag.com"></div>
<div data-id="http://reddit.com"></div>
<div data-id="http://facebook.com"></div>
<div data-id="http://stackoverflow.com"></div>
<div data-id="http://twitter.com"></div>
<div data-id="http://mashable.com"></div>

所以如果存在stackoverflow,则绕过:
$('div[data-id="http://www.stackoverflow"]').length

如何用纯JS实现最快的方法?

编辑:

在尝试后,我发现这更加复杂:

由于我必须先添加内容,然后查找是否存在具有特定值属性的data-id两次,我正在努力通过过程实现尽可能快的方式。

这是我的HTML

<div class="ele" data-id="http://stackoverflow.com">http://stackoverflow.com</div>
<div class="ele" data-id="http://engadget.com">http://engadget.com</div>
<div class="ele" data-id="http://9gag.com">http://9gag.com</div>
<div class="ele" data-id="http://reddit.com">http://reddit.com</div>
<div class="ele" data-id="http://facebook.com">http://facebook.com</div>
<div class="ele" data-id="http://stackoverflow.com">http://stackoverflow.com</div>
<div class="ele" data-id="http://twitter.com">http://twitter.com</div>
<div class="ele" data-id="http://mashable.com">http://mashable.com</div>
<div class="ele" data-id="http://bbc.com">http://bbc.com</div>
<div class="ele" data-id="http://twitter.ca">http://twitter.ca</div>
<div class="ele" data-id="http://google.com">http://google.com</div>
<div class="ele" data-id="http://apple.com">http://apple.com</div>
<div class="ele" data-id="http://cnn.com">http://cnn.com</div>
<div class="ele" data-id="http://imgur.com">http://imgur.com</div>
<div class="ele" data-id="http://9gag.com">http://9gag.com</div>

这里是我的JavaScript代码:

var a = document.getElementsByClassName("ele")
for (i=0;i<a.length;i++) {
    var b = a[i].getAttribute("data-id");
    if (document.querySelectorAll('div[data-id="' + b +'"]').length > 1){
        console.log(a[i])
    }
}

这将输出:
<div class="ele" data-id="http://stackoverflow.com">http://stackoverflow.com</div>
<div class="ele" data-id="http://9gag.com">http://9gag.com</div>
<div class="ele" data-id="http://stackoverflow.com">http://stackoverflow.com</div>
<div class="ele" data-id="http://stackoverflow.com">http://stackoverflow.com</div>
<div class="ele" data-id="http://9gag.com">http://9gag.com</div>

其中9gag.com和stackoverflow.com都存在两次以上。

我该如何只保留每个网址一个并删除其余的? 这是否是最快的方法?


回答你的问题的方法是亲自测试性能。StackOverflow无法准确地回答这个问题。你需要拿出你正在执行操作的实际页面,并在你关心的浏览器上进行一些性能测试。没有保证一次测试能准确代表所有情况。 - user2437417
最终的顺序是否重要? - Jonathan Hall
@Flimzy 恐怕是的。 - jQuerybeast
等一下...你只是想要删除重复的元素吗?如果是这样,只需要进行一次DOM选择,循环遍历元素,并将data-id值放入对象键中。在每个元素上检查是否已经存在于对象中,如果是,则删除该元素。这样你就只需要进行一次DOM选择。 - user2437417
@CrazyTrain 我完全同意,我不是在寻找性能测试,而是在寻找一个我无法解决的问题的答案。如果您阅读了我的最新编辑,我正在尝试找出如何删除具有相同值但只有一个的多个数据属性。 - jQuerybeast
显示剩余2条评论
3个回答

8
document.querySelectorAll('div[data-id="http://www.stackoverflow"]').length;

var a = document.getElementsByClassName("ele")
for (i=0;i<a.length;i++) {
    var b = a[i].getAttribute("data-id");
    var all = document.querySelectorAll('div[data-id="' + b +'"]');
    for (var j = 1; j < all.length; j++){//if there is more than 1 match remove the rest
        all[j].parentNode.removeChild(all[j]);
    }
}

http://jsfiddle.net/ehMML/


1
@VivinPaliath 所以没有选择器 API 吗? - Musa
@T.J.Crowder:好吧……看起来我忘了发布我对该测试所做更新的链接!这是它的链接:http://jsperf.com/qsvsjqs/2 - user2437417
@Musa,你能否帮我检查一下我的编辑?它比我想象的要复杂。 - jQuerybeast
@HBP:当然,但这只能告诉你是否至少有一个。OP需要知道是否有多个。 - user2437417
@Crazy Train:我的jsPerf测试有误,我已经更新了。原帖作者想要避免添加重复项,因此他只需要测试他提出的添加方式,并且使用布尔值存在性测试就足够了:如果测试失败则添加,如果测试成功则不添加。 - HBP
显示剩余11条评论

2
var store = {};

var a = document.getElementsByClassName("ele");

for (var i = 0, len = a.length; i < len; i++) {
    var id = a[i].getAttribute("data-id");
    if (store.hasOwnProperty(id)) {
        a[i].parentNode.removeChild(a[i]);
        i--;
        len--;
    } else
        store[id] = 1;
}

虽然这个代码可以运行,但是在循环中我会收到“Uncaught TypeError: Cannot call method 'getAttribute' of undefined”错误。 - jQuerybeast
@jQuerybeast:哎呀,我遇到了“实时列表”问题。我会更新迭代方式为反向迭代。 - user2437417
谢谢。我还提到了最后一个元素保持不变。所以,栈顶的第一个元素被删除,而最后一个元素保持不变。这样说清楚了吗? - jQuerybeast
@jQuerybeast:啊,没错。我们确实需要一个正向迭代。好的,我会更新代码,在执行删除操作时将计数器递减。 - user2437417
不用谢,我刚刚又加了一个快速更新来递减 len,因为我已经缓存了它。 - user2437417

0
可以使用关联数组吗?
for ( ... ) {
    if ( defined foo[url] )
        next;
    foo[url] = 1;
    // Your logic here
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接