Home > Back-end >  What is the best way to find if there are any duplicates in nested child property in a JavaScript Ob
What is the best way to find if there are any duplicates in nested child property in a JavaScript Ob

Time:07-09

I have an array of objects(Vue 3 prop) like below. The array is for room objects. Each room contains adults and childs array with adult and child objects. Now I need to mark the duplicate names (first and last name together) by adding a property name error (Shown in example).

[
    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "John", "last": "Doe"},
        { "title": "Mrs.", "first": "Jane", "last": "Doe"}
    ],
    "children": [
        { "title": "Ms.", "first": "Jane", "last": "Doe"},
        { "title": "Mr.", "first": "Joe", "last": "Doe" }
    ]
    },

    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "Johny", "last": "Doe",},
        { "title": "Mrs.", "first": "Jane", "last": "Doe",}
    ],
    "children": [
        { "title": "Ms.", "first": "Jane", "last": "Doe"},
        { "title": "Mr.", "first": "Jui", "last": "Doe"}
    ]
    },
]

After I run the function or code in question. The resulting array should look like below.

[
    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "John", "last": "Doe"},
        { "title": "Mrs.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." }
    ],
    "children": [
        { "title": "Ms.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." },
        { "title": "Mr.", "first": "Joe", "last": "Doe" }
    ]
    },

    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "Johny", "last": "Doe", },
        { "title": "Mrs.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." }
    ],
    "children": [
        { "title": "Ms.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." },
        { "title": "Mr.", "first": "Jui", "last": "Doe" }
    ]
    },
]

Update:

This is my first question to Stack Overflow, even though I am regular user of the platform for last 7 years.

I am overwhelmed by the responses and definitely will go through each solution.

I am not a JS developer and tried to make a solution (inspired by
vanowm's comment) that now looks like below. I believe the responses have a better solution.

const isDuplicate = function (names, person) {
    let result = false;
    
    names.forEach(function (name) {
        if(name.first === person.first && name.last === person.last){
            result = true;
        }
    });
    
    return result;
}

const validateNames = function () {
    let names = [];

    rooms.forEach(function (room) {

        room.adults.forEach(function (adult) {
            if (isDuplicate(names, adult)) {
                adult.error = 'Duplicate name, please update.'
                // I can do this because it is a Vue Reactive.
            } else {
                adult.error = ''
                names.push(adult);
            }
        })
        
        room.childs.forEach(function (child) {
            if (isDuplicate(names, child)) {
                child.error = 'Duplicate name, please update.'
            } else {
                child.error = ''
                names.push(child);
            }
        })
    });
};```

CodePudding user response:

Here's my naive attempt

I assumed you want to find duplicates among adults separately from duplicates among children - it's not clear since the only duplicate is Jane Doe and she appears twice as an adult and twice as a child!

const data = [
    {
        RoomType: {},
        Price: {},
        Messages: [],
        CancellationPolicyStatus: "",
        adults: [
            { title: "Mr.", first: "John", last: "Doe" },
            { title: "Mrs.", first: "Jane", last: "Doe" },
        ],
        childs: [
            { title: "Ms.", first: "Jane", last: "Doe" },
            { title: "Mr.", first: "Joe", last: "Doe" },
        ],
    },
    {
        RoomType: {},
        Price: {},
        Messages: [],
        CancellationPolicyStatus: "",
        adults: [
            { title: "Mr.", first: "Johny", last: "Doe" },
            { title: "Mrs.", first: "Jane", last: "Doe" },
        ],
        childs: [
            { title: "Ms.", first: "Jane", last: "Doe" },
            { title: "Mr.", first: "Jui", last: "Doe" },
        ],
    },
];
const store = {};

const findDupe = (o, type) => {
    const key = [o.first, o.last].join();
    const tbl = (store[type] = store[type] || {});
    if (!tbl[key]) {
        tbl[key] = [o];
        return;
    }
    if (tbl[key].length === 1) {
        tbl[key][0].error = "Duplicate name, please update.";
    }
    o.error = "Duplicate name, please update.";
    tbl[key].push(o);
};
data.forEach((record) => {
    record.adults.forEach((adult) => findDupe(adult, "adults"));
    record.childs.forEach((child) => findDupe(child, "childs"));
});
console.log(JSON.stringify(data, null, 4));

CodePudding user response:

Create two objects (database) where first and last names will be stored, iterate your objects and check if first/last name exists in the database, if not, add them to the database:

const arr = [
    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "John", "last": "Doe"},
        { "title": "Mrs.", "first": "Jane", "last": "Doe"}
    ],
    "childs": [
        { "title": "Ms.", "first": "Jane", "last": "Doe"},
        { "title": "Mr.", "first": "Joe", "last": "Doe" }
    ]
    },

    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "Johny", "last": "Doe",},
        { "title": "Mrs.", "first": "Jane", "last": "Doe",}
    ],
    "childs": [
        { "title": "Ms.", "first": "Jane", "last": "Doe"},
        { "title": "Mr.", "first": "Jui", "last": "Doe"}
    ]
    },
];

function check(arr)
{

  //we'll store names for both adults and children in these objects
  const first = {},
        last = {};

  return arr.map(room =>
  {
    const checkDup = person =>
    {
      //check if this first/last name already exists in our database
      if (first[person.first] !== undefined && last[person.last] !== undefined)
      {
        //set error property in current person object
        person.error = "Duplicate name, please update.";
        //set error property in the original person object
        first[person.first].error = person.error;
      }
      else
      {
        //store names in the database
        first[person.first] = person;
        last[person.last] = person;
      }
      return person;
    }
    room.adults.forEach(checkDup);
    room.childs.forEach(checkDup);
    return room;
  });
}

console.log(check(arr));
/*
[
    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "John", "last": "Doe"},
        { "title": "Mrs.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." }
    ],
    "childs": [
        { "title": "Ms.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." },
        { "title": "Mr.", "first": "Joe", "last": "Doe" }
    ]
    },

    {
    "RoomType":{  },
    "Price": {  }, 
    "Messages": [], 
    "CancellationPolicyStatus": "", 
    "adults": [
        { "title": "Mr.", "first": "Johny", "last": "Doe", },
        { "title": "Mrs.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." }
    ],
    "childs": [
        { "title": "Ms.", "first": "Jane", "last": "Doe", "error": "Duplicate name, please update." },
        { "title": "Mr.", "first": "Jui", "last": "Doe" }
    ]
    },
]
*/

not to be a grammar nazzy, but it's children, not childs

CodePudding user response:

There are probably better ways to do this, but this should suit your needs. You'll need to loop over both of the arrays checking the names of each object. Set the error for both adult and child if you come across a match.

Should also be worth noting that your parent array of these objects was not named (unless it is named props, I don't use Vue so I don't know if that is a convention or not) so you would have to loop through every object in the parent array to do this.

const namesArray = [];
// Loop over the adults array. Store the names and index to check against later
adults.forEach((adult, index) => {
  let fullName = adult.first   adult.last;
  namesArray.push({name: fullName, index: index});
}

// Loop over the child array
// If the name of a child is found in the namesArray, set the error for the child and the corresponding adult
children.forEach(child => {
  let fullName = child.first   child.last;
  namesArray.forEach(nameObject => {
    if(nameObject.name === fullName) {
      child.error = 'Duplicate name, please update.';
      adults[nameObject.index].error = 'Duplicate name, please update.';
    }
  } 
}
  • Related