skip to Main Content

I am trying to filter an array for duplicate values by splitting/substring the elements.

I need to split these data by "-" and search for duplicate string after the "-" and write the element with the duplicate string to the duplicate array.

Here is what I am working on:

  var arr = ['abc-10.10.10.0/22','abc-10.01.21.0/22','abc-10.01.01.0/22','abcd-10.01.01.0/22'];
    var duplicates = [];

arr.forEach(function (value, index, array) {
    if (array.indexOf(value, index + 1) !== -1
        && duplicates.indexOf(value) === -1) {
        duplicates.push(value);
    }
});

console.log("Duplicate values:", duplicates); 
//Desired output 'abc-10.01.01.0/22','abcd-10.01.01.0/22'

2

Answers


  1. Using Object.groupBy

    Simplest implementation – just group by the substring, and return all results with a count > 1.

    function getDuplicates(xs, selector) {
        const group = Object.groupBy(xs, selector);
        return Object.keys(group)
            .filter(k => group[k].length > 1)
            .map(k => group[k])
            .flat();
    }
    
    var arr = ['abc-10.10.10.0/22','abc-10.01.21.0/22','abc-10.01.01.0/22','abcd-10.01.01.0/22'];
    getDuplicates(arr, (x) => x.split('-')[1])
    

    Custom Implementation

    In this case, you are trying to solve for a unique on the selector, but keep the original values. With this, we need to keep track both of the duplicate substrings, and what substrings link to the original value.

    This implementation is tightly solved for this problem, and the only benefit is not needing to filter before selecting the values at the cost of an additional set. I don’t think this is worth the possible slight performance gain (code is harder to maintain / less easy to understand, increased space complexity), but I’ve provided it nonetheless.

    function getDuplicates(xs, selector) {
        const selectSet = new Set(); // list of all duplicate found selectors
        const selectToXs = {}; // key of selector to return original values
        for(const x of xs) {
            const sub = selector(x);
            if (sub in selectToXs) {
                selectSet.add(sub);
                selectToXs[sub].add(x);
            } else {
                selectToXs[sub] = new Set([x]);
            }
        }
        return [...selectSet].map((s) => [...selectToXs[s]]).flat();
    }
    
    var arr = ['abc-10.10.10.0/22','abc-10.01.21.0/22','abc-10.01.01.0/22','abcd-10.01.01.0/22'];
    getDuplicates(arr, (x) => x.split('-')[1])
    
    Login or Signup to reply.
  2. probably not optimal:

    const arr = ['abc-10.10.10.0/22','abc-10.01.21.0/22','abc-10.01.01.0/22','abcd-10.01.01.0/22'];
    
    
    const afterSet = new Set();
    const duplicateSet = new Set();
    arr.forEach(str => {
      const afterString = str.split('-').at(1);
      if(afterString !== undefined &&
        afterSet.size === 
        afterSet.add(afterString).size)
          duplicateSet.add(afterString);
    });
    const duplicates = arr.filter(
      str => duplicateSet.has(str.split('-').at(1)));
    
    console.log("Duplicate values:", duplicates); 
    //Desired output 'abc-10.01.01.0/22','abcd-10.01.01.0/22'
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search