javascripthtmlcssnodelist

Javascript group elements with identical classnames


I want to select all elements with class name find-me and group them in separate arrays (or NodeLists) based on their other classes, if idential. Here is an example:

<div class="find-me one two">
  Element 1
</div>
<div class="find-me one two">
  Element 2
</div>
<div class="find-me one two three">
  Element 3
</div>
<div class="find-me one two three">
  Element 4
</div>
<div class="find-me one two four">
  Element 5
</div>
<div class="find-me one two">
  Element 6
</div>
<div class="one two">
  Element 7
</div>

My goal is to have:

I suppose I have to use document.querySelectorAll('.find-me') to first get a NodeList of all the elements I am interested in.

But then? I was thinking I could compare the list of classes from the current element with the previous one but how can I keep track of what element goes to what group? Any idea how to achieve that?


Solution

  • Sounds like a good opportunity to use Object.groupBy, but be aware of its poor coverage

    const groups = Object.groupBy(document.querySelectorAll('.find-me'), e => e.classList);
    
    console.log(groups);
    <div class="find-me one two">
      Element 1
    </div>
    <div class="find-me one two">
      Element 2
    </div>
    <div class="find-me one two three">
      Element 3
    </div>
    <div class="find-me one two three">
      Element 4
    </div>
    <div class="find-me one two four">
      Element 5
    </div>
    <div class="find-me one two">
      Element 6
    </div>
    <div class="one two">
      Element 7
    </div>

    Using the same concept, you can write a reduce function to achieve the same goal, also the order/repetitive classes doesn't matter:

    const groups = [...document.querySelectorAll('.find-me')].reduce((acc, cur) => {
      const key = [...cur.classList].sort();
      acc[key] ??= [];
      // use the following code instead of the line above if you need to support IE11
      // acc[key] || (acc[key] = []);
      acc[key].push(cur);
      return acc;
    }, {});
    
    console.log(groups);
    <div class="find-me one two">
      Element 1
    </div>
    <div class="two find-me one one">
      Element 2
    </div>
    <div class="find-me one two three">
      Element 3
    </div>
    <div class="find-me one three two ">
      Element 4
    </div>
    <div class="find-me one two four">
      Element 5
    </div>
    <div class="find-me one two">
      Element 6
    </div>
    <div class="one two">
      Element 7
    </div>