Set adds same object to the list - Javascript - javascript

Is there a way to check if the objects have the same that before inserting them into the Set?
let mySet = new Set();
let person = {
name: 'John',
age: 21
};
let person2 = {
name: 'John',
age: 21
};
mySet.add(person);
mySet.add(person2);
console.log(JSON.stringify([...mySet]));

Is there a way to check if the objects have the same that before inserting them into the Set?
Only by doing it yourself by iterating the set, since they're different (though equivalent) objects; as is always the case, two different objects aren't "equal" to each other for any of JavaScript's built-in operations. And sets don't offer methods like some or find like arrays do.
For instance, you might use a utility function:
function setFind(set, predicate) {
for (const element of set) {
if (predicate(element)) {
return element;
}
}
}
Then:
if (!setFind(mySet, ({ name, age }) => name === person2.name && age == person2.age)) {
mySet.add(person2);
}
let mySet = new Set();
let person = {
name: 'John',
age: 21
};
let person2 = {
name: 'John',
age: 21
};
mySet.add(person);
if (!setFind(mySet, ({ name, age }) => name === person2.name && age == person2.age)) {
mySet.add(person2);
}
console.log(JSON.stringify([...mySet]));
function setFind(set, predicate) {
for (const element of set) {
if (predicate(element)) {
return element;
}
}
}
Or just use a loop, or use some or find after converting to an array:
let contains = [...mySet].some(({ name, age }) => name === person2.name && age == person2.age);
if (!contains) {
mySet.add(person2);
}
let mySet = new Set();
let person = {
name: 'John',
age: 21
};
let person2 = {
name: 'John',
age: 21
};
mySet.add(person);
let contains = [...mySet].some(({ name, age }) => name === person2.name && age == person2.age);
if (!contains) {
mySet.add(person2);
}
console.log(JSON.stringify([...mySet]));
Or similar.

Related

decompose object to this attributes

I am trying to decompose an object into attributes as follows;
let example = {name: 'Fred', age:20}
const {name, age} = example;
But, I would like it to do to the this.name, and this.age of the class it is in. Something like;
class Test = {
name: ''
age: null
constructor(example) {
{this.name, this.age} = example;
}
}
Is this possible?
It is possible to assign value to objects using destructuring. It is definitely NOT recommended. You can see why:
class Test {
name = ''
age = null
constructor(example) {
({ name: this.name, age: this.age } = example) // <- dont't forget the parenthesis
}
}
console.log(
new Test({ name: 'name', age: 10 })
)
If the properties of example and the class are same, you can just use Object.assign
class Test {
name = ''
age = null
constructor(example) {
Object.assign(this, example)
}
}
console.log(
new Test({ name: 'name', age: 10 })
)

Check if array includes a value

I have an array of objects, and I need to prevent duplicate objects of being added to the array. I've tried the following code to check for duplicates:
const array = [{ name: 'John' }];
const newName = {
name: 'John'
};
console.log(array);
console.log(newName);
if (array.includes(newName)) {
console.log(newName.name + ' exists');
} else {
console.log('name does not exist');
}
Console logging tells that the object NewName is exactly the same as array[0]. However,
if(array.includes(newName))
returns false.
What I'm I doing wrong? I tried the solutions in this post as well with no luck:
How do I check if an array includes an object in JavaScript?
Simply, you can use array.some from
Array.prototype.some() documentation.
In your own example, you can do some tweaks to your program:
const array = [{ name: "John" }];
const newName = {
name: "John"
};
console.log(array);
console.log(newName);
if (array.some(object => object.name === newName.name)) {
console.log(newName.name + " exists");
} else {
console.log("name does not exist");
}
If the name is the identity of the object, you can use some function on array:
const array = [{ name: 'John' }];
const newName = { name: 'John' };
if (array.some(({name}) => name === newName.name)) {
console.log(newName.name + ' exists');
} else {
console.log('name does not exist');
}
Or you can check if the count of properties is the same and then every property with:
const array = [{ name: 'John', age: 33 }, { name: 'John', age: 45 }];
const newName = { age: 33, name: 'John' };
if (array.some(x => Object.keys(x).length === Object.keys(newName).length && Object.keys(x).every(p => x[p] === newName[p]))) {
console.log(newName.name + ' exists');
} else {
console.log('name does not exist');
}
The thing you're missing is that includes checks for identity when you use it on an object. newName has the same properties as the object in your array, but it isn't the same object any more than two people named John are the same person. For a more obvious example, run {} == {} and you'll get false.
To check if the array contains an object with the same name, you can use some and pass it a function to compare the object, e.g.
array.some(e => e.name == newName.name)
use it :
var newName = {
name: 'John'
};
console.log(array);
console.log(newName.name);
var found = array.some(obj => obj.name === newName.name);
if (found) {
console.log(newName.name + ' exists');
} else {
console.log('name does not exist');
}
const array = [{
name: 'John'
}];
const newName = {
name: 'John'
};
let resultArr = array.filter((item) => {
return item.name === newName.name
})
let elementPresentMsg;
if (resultArr.length > 0) {
elementPresentMsg = newName.name + ' exists';
} else {
elementPresentMsg = 'name does not exist'
}
document.getElementById('msg').innerHTML = elementPresentMsg;
<html>
<body>
<p id="msg"></p>
</body>
</html>
If you want to find the name or any other value from array, if attributes of object are same as that in array of objects, the following should be helpful:
const array = [{ name: 'John' }];
const newName = {
name: 'John'
};
let resultArr = array.filter((item) => {
return item.name === newName.name
})
if (resultArr.length > 0) {
alert(newName.name + ' exists'); //any way to print result instead of alert
} else {
alert('name does not exist'); //any way to print result instead of alert
}
That is because array[0] not equal newName. In Javascript, they point to the different element. You can try console.log(array[0] == newName), and you will get false.
If you want to find the duplicates, you can try like this:
if (JSON.stringify(array).indexOf(JSON.stringify(newName)) != -1) {
console.log('exist')
}
else {
console.log('not exist')
}
This is because you are trying to compare two different instances of objects which will never be equal.
But if you convert the objects to primitive strings by doing JSON.stringify you can then use Array.includes for deep comparison. As ttulka pointed out, this will only work if the object to be searched has the properties in the same order as the object to find in the array.
const array = [{ name: 'John', age: 33 }];
const newName = {
name: 'John',
age: 33
};
if (array.map(obj => JSON.stringify(obj)).includes(JSON.stringify(newName))) {
console.log(newName.name + ' exists');
} else {
console.log('name does not exist');
}
If you look into the Array#includes polyfill in MDN, you would see that the comparison happens using the === strict equality operator:
function sameValueZero(x, y) {
return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
}
// 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(valueToFind, elementK) is true, return true.
if (sameValueZero(o[k], valueToFind)) {
return true;
}
// c. Increase k by 1.
k++;
}
So when you compare two different object literals using === they won't be equal:
console.log({name :"John"} === {name :"John"});
But primitive strings on the other hand are equal if you compare them with ===:
console.log('{name:"John"}' === '{name:"John"}');
But the same is not true for String objects:
console.log(new String('{name:"John"}') === new String('{name:"John"}'));

JavaScript - iterate through object and change nested properties

This is an object to be processed:
var q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
I would like to go through each key of q and if the corresponding value is an object that has the property contains then replace it with $regex.
Related information can be found here: JavaScript: Object Rename Key
You can try the following way:
var q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
for(var k in q){
if(q[k].hasOwnProperty('contains')){
Object.defineProperty(q[k], '$regex',
Object.getOwnPropertyDescriptor(q[k], 'contains'));
delete q[k]['contains'];
}
}
console.log(q);
for(const obj of Object.values(q)) {
obj.$regex = obj.contains;
delete obj.contains;
}
Just go over all values inside q and copy the contains property into the $regex property.
To iterate over object keys first you have to fetch them, here is one simple approach
const keys = Object.keys(q); // ["email", "name"]
Now iterate over the array which we got and perform regex testing;
keys.forEach(key => {
let value = q[key].contains;
// create $regex and assign value
// remove .contains
})
You can loop through the objects and first put current value of contains property in $regex and then delete the contains property.
Below is working code:
var q = {
email: {
contains: "noname#hotmail.com"
},
name: {
contains: "someuser"
}
};
for (var i of Object.values(q)) {
if (i.hasOwnProperty("contains")) {
i.$regex = i.contains;
delete i.contains;
}
}
console.log(q);
var q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
Object.keys(q).forEach(k => {
if (typeof q[k].contains != 'undefined'){
q[k].$regex = q[k].contains;
delete q[k].contains;
}
})
console.log(q);
Other version using Es 6 features
const renameProp = (
oldProp,
newProp,
{ [oldProp]: old, ...others }
) => {
return {
[newProp]: old,
...others
};
};
let q = {
email: {contains: "noname#hotmail.com"},
name: {contains: "someuser"}
};
let newObj = {}
for (let propName in q) {
newObj[propName] = renameProp("contains","$regex",q[propName])
}
console.log(newObj)
var q = {
email: {
contains: "noname#hotmail.com"
},
name: {
contains: "someuser"
},
asdf: "asdf"
};
Object.keys(q).forEach(function(item, index) {
if (typeof q[item] == "object" && q[item].contains) {
q[item].$regex = q[item].contains;
delete q[item].contains;
}
})

How to add element key & value to object?

I am trying to add key value from array to person object, i mocked below code similar approach it is coming undefined object when we assign key/value pair to object. What would be right approach to achieve this task ?
main.js
const person = {
Name: "John klmeni"
age: 29
}
const address = [{address: '111 main st"}]
for (let obj in person) {
address.forEach(element ,==> {
obj[key] = element.key
}
}
I think you want to do the following?
const person = {
Name: "John klmeni",
age: 29
}
const address = [{address: '111 main st'}];
const newPerson = address.reduce(
(result,item)=>
Object.assign({},result,item),
person
);
console.log(newPerson);

compare keys of two objects and construct a third one with same keys to reflect the difference

I am trying to compare two objects and construct a third one if the value stored in a property of one is different than the other. If not I am storing an empty string. The way am doing it in my opinion is super inefficient and non sustainable. This wont work if the keys change or their number increases. I have to be able to do this programmatically with pure JS, no jQuery:
var staleProfile = {
firstName: 'john',
lastName: 'smith',
email: 'js#gmail.com'
}
var CurrentCustomer = {};
CurrentCustomer.profile = {
firstName: 'paul',
lastName: 'smith',
email: 'js#yahoo.com'
}
var returnObj = {};
returnObj.firstName = staleProfile.firstName != CurrentCustomer.profile.firstName ? CurrentCustomer.profile.firstName : ''
returnObj.lastName = staleProfile.lastName != CurrentCustomer.profile.lastName ? CurrentCustomer.profile.lastName : ''
returnObj.email = staleProfile.email != CurrentCustomer.profile.email ? CurrentCustomer.profile.email : ''
This searches for all the object keys in the CurrentCustomer.profile and checks for differences to the staleProfile. It adds keys to the diff, that only exist in object1 but not in object0, but doesn't take care of keys that are removed from object0to object1.
var staleProfile = {
firstName: 'john',
lastName: 'smith',
email: 'js#gmail.com',
key0: 'value0'
}
var CurrentCustomer = {};
CurrentCustomer.profile = {
firstName: 'paul',
lastName: 'smith',
email: 'js#yahoo.com',
key1: 'value1'
}
function createDiffObject(object0, object1) {
var diff = {};
Object.keys(object1).forEach(function(key) {
if (!object0.hasOwnProperty(key) || object0[key] != object1[key]) {
diff[key] = object1[key];
} else {
diff[key] = '';
}
});
return diff;
}
console.log(createDiffObject(staleProfile, CurrentCustomer.profile));
// output:
/*
{ firstName: 'paul',
lastName: '',
email: 'js#yahoo.com',
key1: 'value1' }
*/
An option would be to get all the keys present in your object using Object.keys(staleProfile).
After this you can loop through the keys and compare values. See an example down below.
var keys = Object.keys(staleProfile),
i, j,
comparedObject = {},
key,
CurrentCustomer = {
a:a,
b:b,
c:c
};
for (i = 0, j = keys.length; i < j; i++) {
key = keys[i];
if (staleProfile[key] === CurrentCustomer[key]) {
comparedObject[key] === CurrentCustomer[key];
} else {
comparedObject[key] === '';
}
}
One way to do it is to make a small helper function to assign each property (or empty string):
// NOTE: staleProfile and CurrentCustomer are assumed to be in the scope above
// If this could be an issue, just pass them as parameters
function getProp(prop) {
let staleProp = staleProfile[prop];
let currProp = CurrentCustomer.profile[prop];
return staleProp != currProp ? currProp : '';
}
And then use it like:
let returnObj = {
firstName : getProp('firstName'),
lastName : getProp('lastName'),
email : getProp('email')
}
Running Example
var staleProfile = {
firstName: 'john',
lastName: 'smith',
email: 'js#gmail.com'
}
var CurrentCustomer = {};
CurrentCustomer.profile = {
firstName: 'paul',
lastName: 'smith',
email: 'js#yahoo.com'
}
function getProp(prop) {
let staleProp = staleProfile[prop];
let currProp = CurrentCustomer.profile[prop];
return staleProp != currProp ? currProp : '';
}
let returnObj = {
firstName: getProp('firstName'),
lastName: getProp('lastName'),
email: getProp('email')
}
console.log(returnObj);
The advantage of this helper function is that, in case you need to update your strategy for replacement of a missing value, you only have to do it in one place.
Furthermore, you could have an array of keys you would like to extract:
let keys = ['firstName', 'lastName', 'email'];
Or perhaps extract all using Object.keys:
let keys = Object.keys(staleProfile);
And then you can store the keys using the getProp function:
keys.forEach(k => {
returnObj[k] = getProp(k);
});
This would make adding/removing properties simply a matter of the current content the keys array. When you need to remove or add a property, you can either update the keys array in the first example, or update the staleProfile in the second example and let Object.keys return the values for you. Either way, with one small change you can add/remove properties.
Running example:
var staleProfile = {
firstName: 'john',
lastName: 'smith',
email: 'js#gmail.com'
}
var CurrentCustomer = {};
CurrentCustomer.profile = {
firstName: 'paul',
lastName: 'smith',
email: 'js#yahoo.com'
}
function getProp(prop) {
let staleProp = staleProfile[prop];
let currProp = CurrentCustomer.profile[prop];
return staleProp != currProp ? currProp : '';
}
let keys = Object.keys(staleProfile);
let returnObj = {};
keys.forEach(k => {
returnObj[k] = getProp(k);
});
console.log(returnObj);
Note: James Thorpe made a good observation in the comment.
what if one of the future properties you speak of could validly hold an empty string? In that case, you won't know if it's been updated to a an empty string or is unchanged. You may want to consider using null for unchanged items

Categories