Mikkel Fennefoss
Mikkel Fennefoss

Reputation: 911

Returning unique values from multiple data attributes

I have the following markup:

<li data-group="bottoms">Pants</li>
<li data-group="bottoms">Pants</li>
<li data-group="bottoms">Pants</li>
<li data-group="tops">Shirt</li>
<li data-group="tops">T-shirt</li>
<li data-group="tops">Polo</li>
<li data-group="accessories">Sunglasses</li>

Im trying to return a list of the unique data-group names, but I only wanna return it once. Which means from the list above I would like to return a variable that will contain:

My approach to this is to first find the length of the list and then make a for loop which loops over all the elements and prints their data-group value. After that I would have to do some sorting so that the bottoms and tops dont show up 3 times, but only once.

I have tried to write the initial code which looks like this.

var uniqueCategoryGroupNames = document.querySelectorAll('li[data-group]');

for (var k = 0; k < uniqueCategoryGroupNames.length; k++) {
    console.log([k]);
    uniqueCategoryGroupNames[k].getAttribute('data-group');
}

Upvotes: 2

Views: 196

Answers (3)

Sergii Stotskyi
Sergii Stotskyi

Reputation: 5400

The best way is to use new Set object (which stores only unique values) or use old plain object. Also you can use dataset if you support browsers IE11+ (otherwise just replace dataset with getAttribute('data-group'))

Using Set

var lis = document.querySelectorAll('li[data-group]');
var uniqueGroupsSet = Array.from(lis).reduce((all, li) => all.add(li.dataset.group), new Set());
var uniqueGroupNames = Array.from(uniqueGroupsSet);

Using plain object

var lis = document.querySelectorAll('li[data-group]');
var uniqueGroupsSet = Array.from(lis).reduce((all, li) => {
  all[li.dataset.group] = true
  return all
}, {});
var uniqueGroupNames = Object.keys(uniqueGroupsSet);

Combined way: plain object + array

var lis = document.querySelectorAll('li[data-group]');
var uniqueGroupNames = []
Array.from(lis).reduce((all, li) => {
  if (!all[li.dataset.group]) {
    all[li.dataset.group] = true
    uniqueGroupNames.push(li.dataset.group)
  }
  return all
}, {});
console.log(uniqueGroupNames)

Upvotes: 2

Zenoo
Zenoo

Reputation: 12880

You can use a combination of Array#from, Array#reduce and Array#includes:

liArray.reduce(                                       //Go through your Array
  (acc, curr) => 
    acc.includes(curr.getAttribute('data-group')) ?   // Is the current value already stored?
      acc                                             // Then don't add the current value
      : acc.concat([curr.getAttribute('data-group')]) // Else add the value
  , []                                                // Starting value for the accumulator
);

Demo:

let liArray = Array.from(document.querySelectorAll('li[data-group]'));

let result = liArray.reduce((acc, curr) => acc.includes(curr.getAttribute('data-group')) ? acc : acc.concat([curr.getAttribute('data-group')]), []);

console.log(result);
<ul>
  <li data-group="bottoms">Pants</li>
  <li data-group="bottoms">Pants</li>
  <li data-group="bottoms">Pants</li>
  <li data-group="tops">Shirt</li>
  <li data-group="tops">T-shirt</li>
  <li data-group="tops">Polo</li>
  <li data-group="accessories">Sunglasses</li>
</ul>

Upvotes: 3

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

You can declare a array to store that attributes and check for the existence of the attribute before pushing it into the array:

var uniqueCategoryGroupNames = document.querySelectorAll('li[data-group]');
var res = [];
for (var k = 0; k < uniqueCategoryGroupNames.length; k++) {
var attr = uniqueCategoryGroupNames[k].getAttribute('data-group');
  //check that the attribute do not exist in the array
  if(res.indexOf(attr) === -1) {
    res.push(attr);
  }
}
console.log(res);
<li data-group="bottoms">Pants</li>
<li data-group="bottoms">Pants</li>
<li data-group="bottoms">Pants</li>
<li data-group="tops">Shirt</li>
<li data-group="tops">T-shirt</li>
<li data-group="tops">Polo</li>
<li data-group="accessories">Sunglasses</li>

Upvotes: 2

Related Questions