Datacrawler
Datacrawler

Reputation: 2886

Remove duplicates from JSON generated dropdown options

I have a dropdown in HTML and I found an answer in order to exclude the duplicates from the options:

[].slice.call(country.options)
  .map(function(a){
    if(this[a.innerText]){ 
      country.removeChild(a); 
    } else { 
      this[a.innerText]=1; 
    } 
  },{});
<select id="country">
  <option value="USA">United States</option>
  <option value="Ind">India</option>
  <option value="NZ" selected>New Zealand</option> 
    <option value="NZ" >New Zealand</option>
  <option value="SA">South Africa</option>
  <option value="UK">United Kingdom</option>
    <option value="UK">United Kingdom</option>
 <option value="JP">Japan</option>
</select>

which works fine because it is based on the duplicated values.

I am now loading data into an HTML table from a JSON string and after aggregating using JS, I am creating a dropdown filter for some columns. I have managed to remove duplicates by using this:

  if(!rate_filter.includes(result[i][5]))
  {
     rate_filter +='<option value="' + i + '">' + result[i][5] + '</option>';
  }

but it does not always work. Let's say that we have the following values in the dropdown:

My script will exclude the 'AAAA' values because it is included in the 'AAAA & CCCC' string.

So, I either have to delete the IF statement and then use this script (which works if I convert my class to an id):

[].slice.call(rate_filter1.options)
  .map(function(a){
    if(this[a.innerText]){ 
      country.removeChild(a); 
    } else { 
      this[a.innerText]=1; 
    } 
  },{});

which is not going to work in this case as the values in the options are different (0,1,2,3 etc):

<select id="rate_filter1" >
<option value="0">desktop &amp; mobile</option>
<option value="1">mobile</option>
<option value="2">mobile</option>
<option value="3">mobile</option>
</select>

Or, I have to change a part of the script:

  if(!rate_filter.includes(result[i][5]) || result[i][5] != result[i-1][5])
  {
     rate_filter +='<option value="' + i + '">' + result[i][5] + '</option>';
        }

Any suggestions? I have pasted a snippet below with two different versions for the filters. I think I need to add something in the IF statement in order to remove the duplicate. It must be really close.

//Load JSON data

var data = {"headers":["Plat","Head2","Head3","Head4","Head5","Head6","Head7","Head8","Head9","Head10","Head11","Head12","Head13","Head14","Head15","Head16","random2","Head18","Head19"],"rows":[["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24+beauty",784.23,463310,1.6926679760851266,66476,0.011797189963295023,0.14348060693703998,0,0,0,66766,0.011745948536680347,0.14410653773931062],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-34+beauty",524.61,295454,1.7756063549655785,51223,0.01024168830408215,0.17337047391472107,0,0,0,51484,0.010189767694817808,0.1742538601609726],["plat2","display","random1","insta-stories","RR1","mobile","f-16-24+beauty",182.69,218348,0.836691886346566,8025,0.022765109034267914,0.03675325626980783,0,0,0,8025,0.022765109034267914,0.03675325626980783],["plat2","video","random1","video page post","RR1","mobile","f-16-24+beauty",178.66,99419,1.7970408070891881,17355,0.01029443964275425,0.17456421810720285,0,0,0,17770,0.010054023635340461,0.1787384705136845],["plat2","video","random1","insta-stories","RR1","mobile","f-25-34+beauty",123.11,96635,1.2739690588296166,5335,0.023075913776944703,0.05520774046670461,0,0,0,5335,0.023075913776944703,0.05520774046670461],["plat2","video","random1","video page post","RR1","mobile","f-25-34+beauty",120.87,55882,2.1629505028452813,12175,0.009927720739219712,0.21786979707240256,0,0,0,12340,0.009794975688816857,0.22082244729966716],["plat1","display","random1","photo page post","RR2","desktop & mobile","f-16-24+beauty",47.67,35864,1.3291880437207229,0,0,0,0,0,0,54,0.8827777777777778,0.0015056881552531786],["plat1","display","random1","photo page post","RR2","desktop & mobile","f-25-34+beauty",32.949999999999996,24020,1.3717735220649456,0,0,0,0,0,0,29,1.136206896551724,0.0012073272273105745],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","display","random1","photo page post","RR2","desktop & mobile","f-25-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-25",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-26",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-25-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24+lookalike",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-22-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat2","display","random1","photo page post","RR2","mobile","f-21-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-28-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat2","display","random1","photo page post","RR2","mobile","f-16-26",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0]]};


//Aggregate
function transformData(rows) {
  const 
    rowMap = new Map(),
    result = [];
    
  // Iterate over the rows.
  rows.forEach(row => {
    const
      // Create a key, it is the first elements joined together.
      key = row.slice(0,5).join();
      
    // Check if the Map has the generated key...
    if (rowMap.has(key)) {
      // The map has the key, we need to add up the values
      const
        // Get the value for the current key.
        storedRow = rowMap.get(key);
        // Add the value of the current row to the row in the map.
        storedRow[7] += row[7];
				storedRow[8] += row[8];
        storedRow[9] += row[9];
        storedRow[10] += row[10];
        storedRow[11] += row[11];
        storedRow[12] += row[12];
        storedRow[13] += row[13];
        storedRow[14] += row[14];
        storedRow[15] += row[15];
        storedRow[16] += row[16];
        storedRow[17] += row[17];
        storedRow[18] += row[18];
        
    } else {
      // The key doens't exist yet, add the row to the map.
      rowMap.set(key, row);
    }
  });
  
  // Iterate over all the entries in the map and push each value with the
  // summed up value into the array.
  rowMap.forEach(value => {
    result.push(value);
  }); 

  //Create the filter
  var rate_filter = '<div class = "filter"><select multiple class="rate_filter1" data-col="0">';
  
  for (i = 0; i < result.length; i++) 
	{
    var j = 0;
    if(i > 1)
    {
      j == i-1;
    }
    else
    {
      j == 0;
    }  
    //Check for duplicates
    if(!rate_filter.includes(result[i][5]) || result[i][5] != result[j][5])
        {
           rate_filter +='<option value="' + i + '">' + result[i][5] + '</option>';
        }
      
  }
     
  rate_filter +='</select></div>';  
  $("#one").html(rate_filter);
  
 
   
 //Second Version
 
  var general_filter = '<div class = "filter"><select multiple class="general_filter1" data-col="1">';
  
  for (i = 0; i < result.length; i++) 
	{
    if(i > 1)
    {
      j == i-1;
    }
    else
    {
      j == 0;
    }  
    //if((!general_filter.includes(result[i][5])) && (result[i][5] != result[j][5]))
    if(i==0 || result[i][5] != result[j][5])
        {
           general_filter +='<option value="' + i + '">' + result[i][5] + '</option>';
           
        }

  }
     
  general_filter +='</select></div>';
  $("#two").html(general_filter);  
 
 }
 
 data.rows = transformData(data.rows);
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js"></script>

<div id="one"></div>
<div id="two"></div>

Upvotes: 1

Views: 573

Answers (1)

Terry
Terry

Reputation: 66218

The reason why your solution didn't work is that you're using .includes() on a string (rate_filter), not an array. Therefore your comparisons using this logic, if(!rate_filter.includes(...)) is not valid.

If you want to generate a unique list of devices (I call it devices only because of the values "mobile" and "desktop & mobile" you've provided in your code, theoretically it can be named anything else), it is quite simple: you just have to follow these steps:

  1. Generate a unique array containing all these devices. This can be done by iterating through all rows of your results, retrieving the device field (which is identified by it's index of 5), and check if they already exist in the array
    • If they don't exist, you add them to the array
    • If they exist, don't do anything
  2. Iterate through the array again to generate the markup

If you look at the logic above, it can be written like this for your code:

// Store unique array of devices
const devices = [];

// Iterate through your results
result.forEach(item => {

  // Convert to lowercase to allow for easy comparison
  const device = item[5].toLowerCase();

  // If exists, don't do anything
  if (devices.includes(device))
    return false;

  // If does not exist, add it to the unique list and write to HTML
  devices.push(device);
  rate_filter +='<option value="' + device + '">' + device + '</option>';
});

See a proof-of-concept code below:

//Load JSON data

var data = {"headers":["Plat","Head2","Head3","Head4","Head5","Head6","Head7","Head8","Head9","Head10","Head11","Head12","Head13","Head14","Head15","Head16","random2","Head18","Head19"],"rows":[["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24+beauty",784.23,463310,1.6926679760851266,66476,0.011797189963295023,0.14348060693703998,0,0,0,66766,0.011745948536680347,0.14410653773931062],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-34+beauty",524.61,295454,1.7756063549655785,51223,0.01024168830408215,0.17337047391472107,0,0,0,51484,0.010189767694817808,0.1742538601609726],["plat2","display","random1","insta-stories","RR1","mobile","f-16-24+beauty",182.69,218348,0.836691886346566,8025,0.022765109034267914,0.03675325626980783,0,0,0,8025,0.022765109034267914,0.03675325626980783],["plat2","video","random1","video page post","RR1","mobile","f-16-24+beauty",178.66,99419,1.7970408070891881,17355,0.01029443964275425,0.17456421810720285,0,0,0,17770,0.010054023635340461,0.1787384705136845],["plat2","video","random1","insta-stories","RR1","mobile","f-25-34+beauty",123.11,96635,1.2739690588296166,5335,0.023075913776944703,0.05520774046670461,0,0,0,5335,0.023075913776944703,0.05520774046670461],["plat2","video","random1","video page post","RR1","mobile","f-25-34+beauty",120.87,55882,2.1629505028452813,12175,0.009927720739219712,0.21786979707240256,0,0,0,12340,0.009794975688816857,0.22082244729966716],["plat1","display","random1","photo page post","RR2","desktop & mobile","f-16-24+beauty",47.67,35864,1.3291880437207229,0,0,0,0,0,0,54,0.8827777777777778,0.0015056881552531786],["plat1","display","random1","photo page post","RR2","desktop & mobile","f-25-34+beauty",32.949999999999996,24020,1.3717735220649456,0,0,0,0,0,0,29,1.136206896551724,0.0012073272273105745],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","display","random1","photo page post","RR2","desktop & mobile","f-25-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-25",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-26",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-25-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-16-24+lookalike",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-16-24",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-22-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat2","display","random1","photo page post","RR2","mobile","f-21-35",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","mobile","f-28-34",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat2","display","random1","photo page post","RR2","mobile","f-16-26",null,null,0,null,0,"NaN",null,0,0,null,0,0],["plat1","video","random1","video page post","RR1","desktop & mobile","f-25-34",null,null,0,null,0,"NaN",null,0,0,null,0,0]]};


//Aggregate
function transformData(rows) {
  const 
    rowMap = new Map(),
    result = [];
    
  // Iterate over the rows.
  rows.forEach(row => {
    const
      // Create a key, it is the first elements joined together.
      key = row.slice(0,5).join();
      
    // Check if the Map has the generated key...
    if (rowMap.has(key)) {
      // The map has the key, we need to add up the values
      const
        // Get the value for the current key.
        storedRow = rowMap.get(key);
        // Add the value of the current row to the row in the map.
        storedRow[7] += row[7];
				storedRow[8] += row[8];
        storedRow[9] += row[9];
        storedRow[10] += row[10];
        storedRow[11] += row[11];
        storedRow[12] += row[12];
        storedRow[13] += row[13];
        storedRow[14] += row[14];
        storedRow[15] += row[15];
        storedRow[16] += row[16];
        storedRow[17] += row[17];
        storedRow[18] += row[18];
        
    } else {
      // The key doens't exist yet, add the row to the map.
      rowMap.set(key, row);
    }
  });
  
  // Iterate over all the entries in the map and push each value with the
  // summed up value into the array.
  rowMap.forEach(value => {
    result.push(value);
  }); 

  //Create the filter
  var rate_filter = '<div class="filter"><select multiple class="rate_filter1" data-col="0">';
  
  // Create unique index of devices
  const devices = [];
  result.forEach(item => {
    const device = item[5].toLowerCase();
    if (devices.includes(device))
      return false;
    
    rate_filter +='<option value="' + device + '">' + device + '</option>';
    devices.push(device);
  });
     
  rate_filter +='</select></div>';  
  $("#one").html(rate_filter);
 }
 
 data.rows = transformData(data.rows);
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-multiselect/0.9.13/js/bootstrap-multiselect.js"></script>

<div id="one"></div>
<div id="two"></div>

Upvotes: 2

Related Questions