Home > database >  How to find and return duplicate values in array of arrays where duplicate occurrence is equal to ar
How to find and return duplicate values in array of arrays where duplicate occurrence is equal to ar

Time:05-05

I'm looking for an efficient way of returning a duplicate value where the duplicate exists in each array within an array.

const array = [
  ['qwerty'], 
  ['abc', 'qwerty'],
  ['foo', 'qwerty']
]

Qwerty would be returned since it exists in all 3 nested arrays. If it only existed in two, nothing would be returned.

I was thinking something along the lines of

     const arr = [];
                            array.map(item =>
                                item.map((nestedItem) => {
                                    arr.push(nestedItem);
                                    const findDuplicates = (data) =>
                                        data.filter(
                                            (item, index) =>
                                                data.indexOf(item) !== index,
                                        );
                                    if (
                                        findDuplicates(arr).length ===
                                        array.length
                                    ) {
                                        return findDuplicates(arr); // This logic here does not work as the count is 1 vs 3
                                    }
                                }),
                            );

Note there could be more than 3 nest arrays or less.

Definitely this is not the right way, I am still new and not good. TIA

CodePudding user response:

Here's a solution based on Sets and their intersection. You can click on 'Run code snippet' to see it working:

const startArray = [
  ['qwerty'],
  ['abc', 'qwerty'],
  ['foo', 'qwerty']
]

function getIntersection(a, b) {
  var setB = new Set(b);
  return [...new Set(a)].filter(x => setB.has(x));
}

function findCommon(array) {
  let intersection;
  for (let i = 0; i < array.length - 1; i  ) {
    intersection = getIntersection(array[i], array[i   1]);
    if (!intersection.length) {
      return [];
    }
  }
  return intersection;
}

console.log(findCommon(startArray))

CodePudding user response:

function findDuplicate(arr){
    return [...new Set(arr.flat())].filter((str)=> arr.every((inner)=> inner.includes(str)))
}

CodePudding user response:

First, take a look at the snippet below:

function getIntersection(array) {
    if (!Array.isArray(array)) return [];
    for (let currentArray of array) {
        if (!Array.isArray(currentArray)) return [];
    }
    let output = [];
    for (let item of array[0]) {
        let shouldAdd = true;
        for (let arrayIndex = 1; shouldAdd && (arrayIndex < array.length); arrayIndex  ) {
            shouldAdd = shouldAdd && (array[arrayIndex].indexOf(item) >= 0);
        }
        if (shouldAdd) {
            output.push(item);
        }
    }
    return output;
}

const array = [
  ['qwerty', 'qwerty2', 'qwerty3'], 
  ['abc', 'qwerty', 'qwerty3'],
  ['foo', 'qwerty', 'qwerty2', 'qwerty3']
]

console.log(getIntersection(array));

It:

  • has a function called getIntersection that will return the intersection of the arrays of an array of arrays
  • first of all, if the parameter given was not an array, then the intersection is empty set, that is, an empty array
  • second, if we already know that the input is an array, but at least an element of this array is not an array, then we again have empty set as a result
  • we initialize our output as an empty set, we will push all the items we find here
  • since we are searching for the elements that are present in all arrays of the array, we also know that all such elements are in the first array
  • so we iterate the first array and check whether all the elements are present in other arrays
  • to achieve this, for each item we create a shouldAdd variable that's initialized with true, because we have no reason - yet - not to add it
  • we loop the other arrays and we compute the conjunction (logical AND) of shouldAdd and the result of our search of the item in the current array and then store the result into shouldAdd
  • since efficiency is a concern, we stop our inner loop at once if we reach to an array that does not contain the item
  • if shouldAdd is still true after the inner loop, then item is present in all the arrays and we push it into out output
  • we return output; as our result

If we still need to improve efficiency, then we can further improve performance by finding the shortest array and processing it instead of the first one:

    function getIntersection(array) {
        if (!Array.isArray(array)) return [];
        let minimalLengthIndex = undefined;
        for (let currentArrayIndex = 0; currentArrayIndex < array.length; currentArrayIndex  ) {
            if (!Array.isArray(array[currentArrayIndex])) return [];
            if ((minimalLengthIndex === undefined) || (array[minimalLengthIndex].length > array[currentArrayIndex].length)) {
                minimalLengthIndex = currentArrayIndex;
            }
        }
        let output = [];
        for (let item of array[minimalLengthIndex]) {
            console.log(`Processing ${item}`);
            let shouldAdd = true;
            for (let arrayIndex = 0; shouldAdd && (arrayIndex < array.length); arrayIndex  ) {
                if (arrayIndex !== minimalLengthIndex) shouldAdd = shouldAdd && (array[arrayIndex].indexOf(item) >= 0);
            }
            if (shouldAdd) {
                output.push(item);
            }
        }
        return output;
    }

    const array = [
      ['qwerty', 'qwerty2', 'qwerty3', 'abc'], 
      ['abc', 'qwerty', 'qwerty3'],
      ['foo', 'qwerty', 'qwerty2', 'qwerty3', 'abc']
    ]

    console.log(getIntersection(array));

In the snippet above I have added console.log calls into the function to show you that we reduced the steps we have processed in the main loop to optimize performance. However, this is much less readable than the first one, so you should only optimize this way if you really have a performance issue to solve.

CodePudding user response:

const array = [
  ['foo', 'qwerty'],
  ['foo', 'qwerty', 'xyz'],
  ['qwerty'],
  ['abc', 'qwerty', 'foo'],
];


let duplicates = [];

// 1- Sort the array depending on nested arrays' length to reduce the number of iterations in the next step
let sorted = array.sort((a, b) => a.length - b.length)
//console.log(sorted);

//2- check 
sorted[0].forEach(item => {  
  for (const nestedArray of sorted) {
    if (nestedArray.every(arr => arr.includes(item))) {
      duplicates.push(item)
    }
  }
})
console.log('duplicates = ', duplicates);

  • Related