aman
aman

Reputation: 6242

Find in an array of objects duplicate set values

I have a UI which has a HTML table where we can add dynamic rows and columns (angularjs)

The table has 2 static columns ID & Description, rest of the columns are dynamic columns where user has to add one or more columns.(button click) One the Save button click I want to validate if user has added unique dynamic columns or not.

Below Variable holds the array of the rows as below:

 $scope.myTable.Rows 

Below is the array generated when user adds just one dynamic column and 2 rows. Here id & description are the static column whereas "0" is the dynamic column added.

{0: "1111", description: "desc1", id: "1111"}
{0: "2222", description: "desc2", id: "2222"}

Another example when 3 dynamic columns, 3 rows are added:

{0: "a1", 1: "a2", 2: "a3", description: "desc1", id: "1111"}
{0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"}
{0: "a9", 1: "a10", 2: "a11", description: "desc3", id: "3333"}

I want to check if the above array is unique only with the combination of dynamic columns. ie as per the above array set values of dynamic columns 0,1,2 should not be repeated in any other row in the array.

So below array set should not pass validation:

{0: "a1", 1: "a2", 2: "a3", description: "desc1", id: "1111"}
{0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"}
{0: "a1", 1: "a2", 2: "a3", description: "desc3", id: "3333"}

As you see the 3rd row above is similar to 1st row. I dont want to take into account column "id" & "description"

While below is still unique:

{0: "a1", 1: "a2", 2: "a3", description: "desc1", id: "1111"}
{0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"}
{0: "a1", 1: "a2", 2: "a9", description: "desc3", id: "3333"}

I have tried looking at couple of posts here at: How can I check if the array of objects have duplicate property values?

But most of it account for looking at a single property and see if there is duplicate but not at a combined set.

I hope I have provided a clear explanation of my requirement. Let me know if you need more information.

--Updated--

I have tried with as:

 let array = [
  {0: "a1", 1: "a2", 2: "a3", description: "desc1", id: "1111"},
 {0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"},
 {0: "a1", 1: "a2", 2: "a3", description: "desc3", id: "3333"}];

 let jsonRows = JSON.parse(JSON.stringify(array));
 var valueArr = jsonRows.map(function(item){ return item."0" });
   //above gives error: Uncaught SyntaxError: Unexpected string
 var isDuplicate = valueArr.some(function(item, idx){ 
return valueArr.indexOf(item) != idx 
 });

console.log(jsonRows);

Upvotes: 0

Views: 114

Answers (3)

Mark
Mark

Reputation: 532

To paraphrase your question:

Given multiple keys, how do I find all rows in an array where the key:value pair occurs more than once?

I used these rows:

var rows = [
  {0: 'a1', 1: 'a2', 2: 'a3', description: 'desc1', id: '1111'},
  {0: 'a5', 1: 'a6', 2: 'a7', description: 'desc2', id: '2222'},
  {0: 'a1', 1: 'a2', 2: 'a3', description: 'desc3', id: '3333'}
];

My answer is probably a bit verbose:

  1. Recursively walk the array against a separate list of keys I want to be unique.
  2. For each given key, find the number of occurrences of each value for that key.
  3. If the count for the value is > 1, push the row to an array of duplicates

You could shorten the solution using functions like #countBy in Lodash.

function duplicates(arr, keys = []) {
  if (keys.length) {
    const key = keys[0];
    const keyValueCounts = count(arr.map(row => row[key]));

    return duplicates(
      arr.reduce((acc, row) => {
        if (keyValueCounts[row[key]] > 1) {
          return acc.concat(row);
        } else {
          return acc;
        }
      }, []),
      keys.slice(1)
    );
  } else {
    return arr;
  }
}

/// or _.countsBy(arr);
function count(arr) {
  const counts = {};

  arr.forEach(value => {
    counts[value] = Number.isInteger(counts[value])
      ? counts[value] + 1
      : 1;
  });

  return counts;
}

console.log(duplicates(rows, [0, 1, 2]));

Upvotes: 1

Dipak
Dipak

Reputation: 6940

This is what I think we can do here very simply, create a map with key as the value of each dynamic property of each row. Take each row and add to map if there is already a property exist duplicate item found.

I have combined each value to make a unique key using a || as the separator, use a unique one which won't be a value for the dynamic property.

 function isUniqueData(data) {
    let map = {}, isUnique = true;
    data.filter(function(item, index) {
      let prop = "";
      for(var key in item) {
        if(key != "description" && key != "id") {
          prop += item[key] + "||";
        }  
      }
      if(map[prop]) {
        isUnique = false;
      } else {
        map[prop] = item;
      }
    }); 
    return isUnique;
 }

var data1 = [
  {0: "a1", 1: "a2", 2: "a3", description: "desc1", id: "1111"},
  {0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"},
  {0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"},
  {0: "a1", 1: "a2", 2: "a9", description: "desc3", id: "3333"}
];
console.log(isUniqueData(data1))

var data2 = [
  {0: "a1", 1: "a2", description: "desc1", id: "1111"},
  {0: "a5", 1: "a6", description: "desc2", id: "2222"},
  {0: "a1", 1: "a4", description: "desc3", id: "3333"}
];
console.log(isUniqueData(data2))

Upvotes: 1

Luca Kiebel
Luca Kiebel

Reputation: 10096

You can write a function that look at all elements until it finds two that have the same 0, 1 and 2 properties:

let testData = [{0: "a1", 1: "a2", 2: "a3", description: "desc1", id: "1111"},{0: "a5", 1: "a6", 2: "a7", description: "desc2", id: "2222"},{0: "a1", 1: "a2", 2: "a3", description: "desc3", id: "3333"}]


function areElementsUnique(arr) {
  if (arr.length === 1) return true; // no need to check if there is only one element
  for (el of arr) {
    if (arr.filter(elm => (el[0] === elm[0] && el[1] === elm[1] && el[2] === elm[2])).length > 1)
      return false
  };
  return true;
}

console.log(areElementsUnique(testData));

Upvotes: 0

Related Questions