Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Highlight duplicate row values JavaScript

I'm using JS to highlight duplicate values in a table.

What basically the code is doing is adding table rows value in an array and then comparing if it exist and then highlights that row.

The code is working fine but it highlights all duplicate values in the same color(red). What i need it to do is to highlight each group of similar values in different color. Lets say i have 4 group of duplicate values, each group should be highlighted in a different color. Maybe colors need to be generated randomly as there maybe multiple duplicate values in the table.

 $(function() {
    var tableRows = $("#sortable tbody tr"); //find all the rows
    var rowValues = []; //to keep track of which values appear more than once
    tableRows.each(function() { 
        var rowValue = $(this).find(".content").html();
        if (!rowValues[rowValue]) {
            var rowComposite = new Object();
            rowComposite.count = 1;
            rowComposite.row = this;
            rowValues[rowValue] = rowComposite;
        } else {
            var rowComposite = rowValues[rowValue];
            if (rowComposite.count == 1) {
                $(rowComposite.row).css('backgroundColor', 'red');
            }
            $(this).css('backgroundColor', 'red');
            rowComposite.count++;
        }
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="sortable">
    <tbody>
        <tr>
            <td class="content">A</td>
        </tr>
        <tr>
            <td class="content">B</td>
        </tr>
        <tr>
            <td class="content">A</td>
        </tr>
         <tr>
            <td class="content">C</td>
        </tr>
         <tr>
            <td class="content">C</td>
        </tr>
    </tbody>
</table>
like image 790
user2334436 Avatar asked Jul 13 '26 19:07

user2334436


2 Answers

Instead of using an array for the rowValues, you better use an object so you can check over the existence of the key value.

You can also use an array of colors from where you get your dynamic colors and keep shifting the array, whenever you find a new value, so each distinct value would have its relevant distinct color.

And there's no need to check for the count in the else block, because whenever you reach this block it means that this value already exists in the array.

This is how should be your code:

$(function() {
  var tableRows = $("#sortable tbody tr"); //find all the rows
  var colors = ["red", "blue", "green", "yellow", "#f5b"];
  var rowValues = {};
  tableRows.each(function() {
    var rowValue = $(this).find(".content").html();
    if (!rowValues[rowValue]) {
      var rowComposite = new Object();
      rowComposite.count = 1;
      rowComposite.row = this;
      rowValues[rowValue] = rowComposite;
    } else {
      var rowComposite = rowValues[rowValue];
      if (!rowComposite.color) {
        rowComposite.color = colors.shift();
      }
      rowComposite.count++;
      $(this).css('backgroundColor', rowComposite.color);
      $(rowComposite.row).css('backgroundColor', rowComposite.color);
    }
  });
});

Demo:

$(function() {
  var tableRows = $("#sortable tbody tr"); //find all the rows
  var colors = ["red", "blue", "green", "yellow", "#f5b"];
  var rowValues = {};
  tableRows.each(function() {
    var rowValue = $(this).find(".content").html();
    if (!rowValues[rowValue]) {
      var rowComposite = new Object();
      rowComposite.count = 1;
      rowComposite.row = this;
      rowComposite.color = colors.shift();
      rowValues[rowValue] = rowComposite;
    } else {
      var rowComposite = rowValues[rowValue];
      rowComposite.count++;
      $(this).css('backgroundColor', rowComposite.color);
      $(rowComposite.row).css('backgroundColor', rowComposite.color);
    }
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="sortable">
  <tbody>
    <tr>
      <td class="content">A</td>
    </tr>
    <tr>
      <td class="content">B</td>
    </tr>
    <tr>
      <td class="content">A</td>
    </tr>
    <tr>
      <td class="content">C</td>
    </tr>
    <tr>
      <td class="content">C</td>
    </tr>
  </tbody>
</table>
like image 197
cнŝdk Avatar answered Jul 16 '26 08:07

cнŝdk


I'd create an array per content text with the cells that have the same content. Once you have this you can iterate over it and highlight the cells as needed.

To generate the random color I've added a method which has a Set to keep track of the generated colors. It will check if a random generator color has been made before and keeps generating colors until a unique color is generated.

It is possible you wind up with colors that make the text illegible or two random color that don't have enough contrast to tell them apart. So it is not a perfect solution.

function generateRandomInt(max, min = 0) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

/**
 * This method will return a new method, when the returned method is 
 * called it will return a unique color. Subsequent calls to the color
 * generator will never return the same color.
 */
function colorGenerator() {
  // Create a Set at the function scope which we can use to keep
  // track of the colors generated by the returned method.
  const
    generatedColors = new Set();
    
  return () => {
    let randomColor;
    // Keep generating a random color in the format "rgb(R,G,B)" until 
    // a color is generated that doesn't yet exist in the set. This doesn't
    // take into account that at some point you'll run out of 
    // possible colors (but it will take 16M+ tries).
    do {
      randomColor = `rgb(${generateRandomInt(255)},${generateRandomInt(255)},${generateRandomInt(255)})`;
    } while (generatedColors.has(randomColor));
    
    // Add the generated, unique, color to the set.
    generatedColors.add(randomColor);
    
    // Return the random color.
    return randomColor;  
  };
}

function highlightDoubles(table) {
  const
    // Get all the element with the content CSS class.
    contentCells = table.querySelectorAll('.content'),
    // Create map, the cell content will be the key and the value will be
    // an array with cells that have the key as content.
    contentMap = new Map();
   
  // IE doesn't support forEach on a NodeList, convert it to an array first.
  Array.from(contentCells).forEach(cell => {
    const
      // For each cell check if the content has been encountered before. If so
      // return the map value and else create a new array.
      array = (contentMap.has(cell.textContent))
        ? contentMap.get(cell.textContent)
        : [];
      // Push the current cell into the array.
      array.push(cell)
      // Store the array in the map.
      contentMap.set(cell.textContent, array);
  });

  // Create a color generator, it will create a random
  // color but never the same color twice.
  const 
    randomColor = colorGenerator();
    
  // Iterate over all the entries in the map, each entry is a unique 
  // cell content text
  contentMap.forEach(cells => {
    // When the lengths of the cells array is less than 2 it means 
    // it is not multiple times in the table. Exit now.
    if (cells.length < 2) {
      return;
    }
    
    // Generate a random color for the current content text. This is just
    // a very naive implementation. It doesn't make any promises on readability.
    const
      color = randomColor();
      
    // Apply the random color to all the cells with the same content.
    cells.forEach(cell => {
      cell.style.backgroundColor = color;
    });
  });
}

highlightDoubles(document.getElementById('sortable'));
<table id="sortable">
    <tbody>
        <tr>
            <td class="content">A</td>
        </tr>
        <tr>
            <td class="content">B</td>
        </tr>
        <tr>
            <td class="content">A</td>
        </tr>
         <tr>
            <td class="content">C</td>
        </tr>
         <tr>
            <td class="content">C</td>
        </tr>
    </tbody>
</table>
like image 42
Thijs Avatar answered Jul 16 '26 08:07

Thijs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!