2

I have an requirement in JS where, i want to get the count of li element which has the same inner value. What is the best way to do it ? I know we can achieve this in Jquery easily using find and contains but i don't want to use jquery.

I want the length of li elements has the Same Value.

For Eg: Say i want to find out how many LI has the value 'A'.

Below is the JS i have tried, which i think is not the best cos if i have say around 10,000 LI then i will have to loop through all the elements get their values and check if its what i want or no, which will surely hit the performance.

Note : LI element is added runtime with their Value.

HTML

<ul class="s_1" id="ULE">
    <li class="r1">A</li>
    <li class="r1">A</li>    
    <li class="r1">B</li>
    <li class="r1">A</li>  
</ul>  

JS

var LI = document.getElementsByClassName('r1');
var cnt = 0;
for(var i=0;i<LI.length;i+=1){
    if(LI[i].innerHTML == 'A'){
        cnt += 1;
    }
}

if(cnt === 4) 
      alert('working good!!');

JS Fiddle

  • 1
    What's wrong with your code? If you add another `A` element, there are 4 of them and the alert happens. – Barmar Aug 21 '14 at 07:33
  • Possible that you neee use === instead of == – SBD Aug 21 '14 at 07:34
  • 2
    @Marciano Why would you need to do that when you know it only contains a number? – Barmar Aug 21 '14 at 07:35
  • 2
    @Barmar ???`innerHTML` contains number??? – Teemu Aug 21 '14 at 07:36
  • `if(cnt === 4)` is just adding confusion to your question – Roko C. Buljan Aug 21 '14 at 07:37
  • Sorry, thought you were talking about `cnt`. But there's no need to use `===` when comparing with `'A'`. – Barmar Aug 21 '14 at 07:37
  • Your code works fine, see http://jsfiddle.net/barmar/uvg5veeL/2/ – Barmar Aug 21 '14 at 07:37
  • Side note: I'd use `document.querySelectorAll(".r1")` rather than `document.getElementsByClassName("r1")`. It has better cross-browser support (such as IE8). – T.J. Crowder Aug 21 '14 at 07:39
  • *"I know we can achieve this in Jquery easily using find and contains but i don't want to use jquery."* jQuery's not going to do it any faster for you. jQuery is just a layer on top of the DOM (with lots of useful stuff in it). If you're using the DOM directly, unless you're doing it in a roundabout fashion (you're not), jQuery's not going to do it any faster for you. – T.J. Crowder Aug 21 '14 at 07:42
  • if(cnt === 4) is just for example. 4 is not hard coded it depends on some value that comes from server. Main question here is for performance – Sharath Bangera Aug 21 '14 at 09:10
  • @Barmar == only checks what type the object is, not the precise string. Read here: http://stackoverflow.com/questions/523643/difference-between-and-in-javascript – SBD Aug 21 '14 at 20:04
  • @Marciano You're crazy. Of course it compares the strings. The difference between `===` and `==` is what happens when the two arguments are different types. `==` will coerce one of them to the other type and then compare the values, `===` will not coerce and always considers them unequal. – Barmar Aug 21 '14 at 20:47
  • @Marciano `==` will sometimes say things are equal when `===` says they're not. It's never the case that `==` says they're unequal but `===` says they are. – Barmar Aug 21 '14 at 20:50
  • @Barmar My sentence is confusing, my bad. But the point what I am trying to make is that === checks the exact value of an object, not only the object type. – SBD Aug 21 '14 at 21:09
  • @Marciano I know. But in this case, how would that help? `innerHTML` is either a string or `null`. When it's a string, `innerHTML == 'A'` will compare them just like `===` does. If it's null, `null == 'A'` will never be true, and changing it to `===` won't change that. – Barmar Aug 21 '14 at 21:17

2 Answers2

2

I don't think there is a better way to improve the performance. If you have nothing but the DOM to work with (e.g. if the data is from user input), and not the underlying data structure from which you created the data, AFAICT there is no other structure to collect all of the elements than into an array-type structure, which will then require O(n) time to check every element.

Rather than have a count target, which is therefore dependent on the amount of list elements, try instead a function to handle the data, which increases the convenience somewhat:

function isEveryElementEqual(nodeList) {
    val = nodeList[0].innerHTML;
    for (var i=1; i<nodeList.length; i++) {
        if (nodeList[i].innerHTML !== val) return false;
    }
    return true;
}

var LI = document.getElementsByClassName('r1');

console.log(isEveryElementEqual(LI)); // Returns false with the above HTML
jayelm
  • 7,236
  • 5
  • 43
  • 61
1

You don't have to search all <li> in the document. getElementsByClassName can be applied to an element, it will then only search within that element. So you can do:

var LI = document.getElementById('ULE').getElementsByClassName('r1');

DEMO

You can also simplify this with querySelectorAll:

var LI = docuement.querySelectorAll('#ULE .r1');
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Excellent point about working only within the desired element. Re your second example, remember that selectors are processed right-to-left, so your simplified solution first finds elements with the class `.r1`, then eliminates ones that aren't descendants of `#ULE`. `document.getElementById("ULE").querySelectorAll(".r1");` is dramatically faster in a large DOM. – T.J. Crowder Aug 21 '14 at 07:50
  • I've read `querySelectorAll` is slower than getting by `id` / `className`. –  Aug 21 '14 at 07:50
  • @Eclecticist: `getElementById` is **dramatically** faster than any other method of finding elements. On most browsers that have it, `getElementsByClassName` is indeed faster than `querySelectorAll`, presumably because it doesn't have to do full selector parsing and generalized matching. It's not likely to *matter*, but... :-) – T.J. Crowder Aug 21 '14 at 07:53
  • Probably, since it has to parse the selector and then figure out what to do, and what to do is what getting by id and classname does. – Barmar Aug 21 '14 at 07:53
  • @Barmar: I realized I'd made *the classic* stupid mistake above: I made an assumption about browser code performance which I hadn't tested. But I got lucky this time and was correct *(whew)*: http://jsperf.com/selector-with-id-root-vs-get-by-id-and-select :-) – T.J. Crowder Aug 21 '14 at 08:00
  • But even faster is my first version: http://jsperf.com/selector-with-id-root-vs-get-by-id-and-select/2 – Barmar Aug 21 '14 at 08:16