Find duplicate values with a JavaScript Map

Count exact duplicate IDs in one pass, preserve meaningful leading zeroes and show a readable result without constructing selectors from input.

Live example

Spot the repeats.

Add product IDs, separated by commas or new lines. Matching is case-sensitive; spaces around each ID are ignored.

Up to 40 IDs and 2,000 characters. This only checks your example; nothing is sent or saved.

apple appears twice.

In this example, apple appears twice. Enable JavaScript to check another list.

Find repeated IDs before carrying on

A product picker or pasted list often needs to identify repeated values. Count the values with a Map, then return every value whose count is greater than one. There is no need for nested comparisons or a selector assembled from user input.

The demo accepts comma- or newline-separated values, trims surrounding whitespace, ignores blank entries and compares case-sensitively. It runs only in your browser and does not submit a form.

Copyable helper

function findDuplicates(values) {
  const counts = new Map();
  for (const value of values) {
    counts.set(value, (counts.get(value) ?? 0) + 1);
  }
  return [...counts]
    .filter(([, count]) => count > 1)
    .map(([value, count]) => ({ value, count }));
}

function parseValues(text) {
  if (text.length > 2000) throw new Error('Use no more than 2,000 characters.');
  const values = text.split(/[,\n]/).map(value => value.trim()).filter(Boolean);
  if (values.length > 40) throw new Error('Use no more than 40 values.');
  return values;
}

console.log(findDuplicates(parseValues('001, 2, 001, Example, example')));
// [{ value: '001', count: 2 }]

An empty list and a one-item list both return no duplicates. The first occurrence determines the order of the returned duplicate groups.

Use it with page elements

For existing, trusted markup with data-product-id attributes:

const rows = [...document.querySelectorAll('[data-product-id]')];
const duplicateIds = new Set(
  findDuplicates(rows.map(row => row.dataset.productId))
    .map(item => item.value),
);

for (const row of rows) {
  row.classList.toggle('has-duplicate', duplicateIds.has(row.dataset.productId));
}

Use a real button to trigger an interactive check and a visible text message to explain the result. Colour alone is not enough. Write any supplied values with textContent, not innerHTML.

Decide what counts as the same value

001 and 1 are different strings here, as are Example and example. If your domain treats them as equivalent, normalise deliberately before counting. Do not silently change case or strip leading zeroes from arbitrary IDs. For a real submission, repeat the check on the server and use an appropriate uniqueness constraint where concurrent writes are possible.

Reference: JavaScript Map.

Original version4 May 2014

Kept here for reference and earlier links. The updated guide above is the recommended starting point; older code may depend on retired services or different software versions.

Demo:

1
2
3

Click

Clicking the above click box, you will notice the first element and third element get a red background, as they both have a data-productid value of “1”.

JsFiddle here also

This code byte is all about detecting duplicate elements, products or just about anything on a web page.

I've tried to keep the code fairly open to allow for tweaking for your own needs.

The basic principle of the example code:

  1. User Presses a button.
  2. Javascript runs to detect if more than 1 of the chosen elements is present. (in this case elements with product-item class, and a productid).
  3. Compares if more than 1 of the same data-productid is present.
  4. If so, prevent form from submitting, and highlight the duplicated elements.

The basic HTML:

<div data-productid="1" class="product-item">1</div>
<div data-productid="2" class="product-item">2</div>
<div data-productid="1" class="product-item">3</div>

<div id="submitform">Click</div>

The JavaScript:

function eliminateDuplicates(A) { // finds any duplicate array elements using the fewest possible comparison
  var i, j, n;
  var d;
  n = A.length;
  // to ensure the fewest possible comparisons
  for (i = 0; i < n; i++) { // outer loop uses each item i at 0 through n
    for (j = i + 1; j < n; j++) { // inner loop only compares items j at i+1 to n
      if (A[i] == A[j]) {
        console.log(A[i]);
        el = $('*[data-productid="' + A[i] + '"]');
        console.log(A[j]);
        el.css({
          "background": "red"
        });
        d = "no";
      } else {
        if (d != "no") {
          d = "yes"
        };
      }
    }
  }
  return d;
}
$('#submitform').click(function (e) {
  var a = [];
  $(".product-item").each(function () {
    a.push($(this).data('productid'));
  });
  $x = eliminateDuplicates(a);
  if ($x == "yes") {
    $('#formid').submit();
  } else {
    e.preventDefault();
    alert("Duplicate entry of same product twice");
  }
});

Keep exploring

A couple more useful notes.