Comparing two large sets of attributes
Suppose you have a Django view that has two functions:
The first function renders some XML using a XSLT stylesheet and produces a div with 1000 subelements like this:
<div id="myText">
<p id="p1"><a class="note-p1" href="#" style="display:none" target="bot">✽</a></strong>Lorem ipsum</p>
<p id="p2"><a class="note-p2" href="#" style="display:none" target="bot">✽</a></strong>Foo bar</p>
<p id="p3"><a class="note-p3" href="#" style="display:none" target="bot">✽</a></strong>Chocolate peanut butter</p>
(etc for 1000 lines)
<p id="p1000"><a class="note-p1000" href="#" style="display:none" target="bot">✽</a></strong>Go Yankees!</p>
</div>
The second function renders another XML document using another stylesheet to produce a div like this:
<div id="myNotes">
<p id="n1"><cite class="note-p1"><sup>1</sup><span>Trololo</span></cite></p>
<p id="n2"><cite class="note-p1"><sup>2</sup><span>Trololo</span></cite></p>
<p id="n3"><cite class="note-p2"><sup>3</sup><span>lololo</span></cite></p>
(etc for n lines)
<p id="n"><cite class="note-p885"><sup>n</sup><span>lololo</span></cite></p>
&开发者_如何学Clt;/div>
I need to see which elements in #myText have classes that match elements in #myNotes, and display them. I can do this using the following jQuery:
$('#myText').find('a').each(function() {
var $anchor = $(this);
$('#myNotes').find('cite').each(function() {
if($(this).attr('class') == $anchor.attr('class')) {
$anchor.show();
});
});
However this is incredibly slow and inefficient for a large number of comparisons.
What is the fastest/most efficient way to do this - is there a jQuery/js method that is reasonable for a large number of items? Or do I need to reengineer the Django code to do the work before passing it to the template?
For best-possible performance, make an index once and then re-use it:
function revealCite() {
var cites_index = $("#myText").data("cites_index");
// if no cached index exists, prepare one (one-time hit code section)
if (!cites_index) {
var cites = $("#myNotes cite");
var cites_count = cites.length();
var cites_index = {};
for (var i=0; i<cites_count; i++) {
var cite = cites[i], group = cites_index[cite.className];
if (!group) cites_index[cite.className] = [];
group.push(cite);
}
$("#myText").data("cites_index", cites_index);
}
// use the index to work with related elements ("this" must be an <a> element)
$(cites_index[this.className]).show();
}
Now trigger the above function any way you like:
$("#myText a").each(revealCite);
PS: You could also do this, in place of the for loop:
cites.each( function() {
var group = cites_index[this.className];
if (!group) cites_index[this.className] = [];
group.push(this);
});
But it's the same number lof lines of code, and probably is a bit slower.
How about something like this:
http://jsfiddle.net/9eXws/
$('#myText a').each(function() {
$("#myNotes ." + $(this).attr('class')).show();
});
Instead of doing an inner each, it simply appends the class for the current a
element into the selector, and performs a show()
on any items found.
I think the inner find
is redundantly re-executing for every iteration of the outer each
. Try storing the matched elements in a variable before the looping commences. I've also tweaked your solution to get class names via the DOM attribute as opposed to using jQuery's attr
:
var $cites = $('#myNotes').find('cite');
$('#myText').find('a').each(function() {
var anchor = this;
$cites.each(function() {
if(this.className == anchor.className) {
$anchor.show();
});
});
Instead of always looping through every element and comparing each of them, you should use Jquery's selectors to do the search for you. This should work significantly faster:
$('#myText > a').each(function() {
var $anchor = $(this);
var anchor_class = $(this).attr('class');
var elements = $('#myNotes > cite[class=' + anchor_class + ']');
if (elements[0] != undefined) {
$anchor.show();
}
});
精彩评论