How to merge multiple objects - javascript

Hello I am new in react native and I want to merge data using Object.assign().
I tried with simple arrays and everythings work but my array is more than array in one big array.
My code:
let o1 = getCartData; // [{productId:56, productQuantity:1}, {productId:4, productQuantity:1}]
let o2 = resultObject; // product with different quantity {productId:56, productQuantity:5}
let finalObj = Object.assign([], o1, o2);
console.log('Final', finalObj); // Output ▼["[","{",""","p","r","o","d","u","c","t","I","d",""",":","5","6",",",""","p","r","o","d","u","c","t","Q","u","a","n","t","i","t","y",""",":","1","}","]"]
I want to get this output:
console.log('Final', finalObj); // Merged [{productId:56, productQuantity:5}, {productId:4, productQuantity:1}]
I tried based on this page

You can map it, Please let me know if this is what you need:
var obj1=[{productId:56, productQuantity:1}, {productId:4, productQuantity:1}];
var obj2={productId:56, productQuantity:5};
var result = obj1.map(({productId, productQuantity})=>({ productId, productQuantity: obj2[`productId`]==productId ? obj2.productQuantity : productQuantity}));
console.log(result);
Or you can make use of reduce method to group data:
var obj1=[{productId:56, productQuantity:1}, {productId:4, productQuantity:1}];
var obj2={productId:56, productQuantity:5};
var result = [...obj1, obj2].reduce((acc, {productId, productQuantity})=>{
acc[productId] = acc[productId] || {productId, productQuantity};
acc[productId].productQuantity = productQuantity;
return acc;
},{});
console.log(Object.values(result));

You can do this using map and find:
arr1.map(arrObj => arr2.find(arr2Obj => arr2Obj.productId === arrObj.productId) || arrObj);
What this code does is:
Inside the array of objects, it iterates through each object, in here each object is called arrObj.
For each object called arrObj we assign an operation using the arrow operator (=>), that operation is going to return a value.
Now we use array.find(()=>{}), which will seek on the second array and will search for every item inside the second array and we put a conditional for it, if the conditional is true, it will return the value of the found item, if not it will return null.
We use a (||) operator that will trigger when the item is not found, we return the object itself, as there is no other object found with the same Id.
Notice that this code works for comparing two arrays, in your example you are trying to compare an array with an object, it can be easily solved if your o2 is equal to [resultObject] (Inside the [brackets] to turn it into an array).
Got this solution from here: Replacing objects in array

Related

JS reduceRight is causing arrays to become objects, how can I fix the logic?

I have an json object:
json = {
"array": [80, 50]
}
A third party jsoneditor, returns a path variable as a list of strings or index to the value. I use event listeners to detect changes to the value and I store those changes in a separate object to later submit to a form.
For example, if I change 50 to 60, this is what is returned:
node.path = ["array", 1]
node.value = 60
I am using reduceRight() to normally map the changes to the object to the changed object, however when the value is an Array it is converting the array to an object.
let delta = node.path.reduceRight((obj, elem) => ({[elem]: obj}), node.value)
//returns
delta = {array: {1: 60}}
//instead of
delta = {array: [80, 60]}
How can I check the original json and if the field is an Array object, don't reduce this into an object but keep the original Array and update the Array with the changed value within the Array? I need to submit the entire array into the form.
EDIT:
I know that I can do some custom logic within the reduce to check the original json and get the unchanged part of the array. I just dont know how to achieve that
let delta = node.path.reduceRight( function (obj, elem) {
//some logic here to account for arrays and get original array list and change only slected index
else {
return {[elem]: obj}), node.value
}
});
EDIT:
Alternatively, how can can I get the nested keys from the node.path and find the original array and then just update the array index? The path can sometimes be nested sothe path is always going to be the Array-like structure.
//this does not work
let orig_key_val = json[node.path]
Thanks!
This seems to work, finally... I used a regular reduce() and check if the key is an Array if it is store my original Array into a tmp object and save that key. The next time the reduce() comes around, if the index is on the last path element then set the tmp[tmp_key][key] to my target value and return the adjusted for Array object instead.
I can see how this will not work for nested json objects but for now I dont have any... Unless someone can show me how to figure that one out this is my implementation for now.
let tmp = {};
let tmp_key;
let delta = node.path.reduce((val, key, index, array) => {
if (Array.isArray(json[key])) {
tmp[key] = json[key]
tmp_key = key;
} else if (Object.keys(tmp).length !== 0 && index === node.path.length-1) {
tmp[tmp_key][key] = node.value;
return tmp
} else
return {[key]: val}
}, node.value);

How do the map function that return an object with modified keys? (JS, React.js)

I am trying to create an object with modified keys after map() function (the data is from API), here is my code:
const getData = mySchedule.schedules.map((data) => ({
[data.id]: false,
}));
setCheckId(getData);
This code return:
And I want this output:
Do you have any solution for this case? thank you.
Solution:
Create an object => const getData = {};
Iterate => mySchedule.schedules
Set id as a key and false as value => getData[item.id] = false;
const getData = {};
mySchedule.schedules.forEach(item => {
getData[item.id] = false;
});
setCheckId(getData);
The above answer is correct, but let's dive deep into the problem first:
The map function returns an Array, what you want is an Object. The map function applies the callback for every element and returns a new array of elements modified by the callback function. What are you seeing is the array returned by the map function, note that 1,2,3,4is the index position of the array. Read more about the function map here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
The output that you want is an object, but as we have learned before the map function always returns an array with new elements resulting from your map function callback.
If you want an object that are many ways to achieve that, you can loop through the array and add properties to the object.
If you want to understand more and dive into array methods, you can even achieve that using reduce method, therefore the first answer is simpler:
/* Another example using reducer */
const data = [ {10:false,20:false}];
const reducer = (accumulator, currentValue) => currentValue[accumulator] = false;
setCheckId(data.reduce(reducer));

Array of objects and i want to return true if any key value pair in the object is duplicate

I am fairly new to JS, I am struggling with a problem where there is an array of objects and i want to return true if any key value pair in the object is duplicate
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}]}
Since key: "Xiomi" came twice so function should return true
i tried using lodash functions
var uniqueLookup =_uniqBy(lookupValues,'key')
if(_.isEqual(uniqueLookup, lookup)) return true
works but i guess i am missing something
You are on the right track. Compare the length of the array to the array shortened by checking if the key is unique.
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}];
console.log(_.uniqBy(lookupValues,"key").length !== lookupValues.length);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.19/lodash.min.js"></script>
Here how you can do this in VanillaJs.
Set is a new data structure that JavaScript got in ES6. It’s a collection of unique values. We put into that the list of property values we get from using map(), which how we used it will return this array:
[xiomi,Samsung,blackberry,xiomi,asus]
Passing through Set, we’ll remove the duplicates i.e xiomi and at last ... is the spread operator, which will expand the Set values into an array.
Now if length of this new array is equal to your lookupValues.length then it has no duplicates else duplicates are present.
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}]
const isDuplicate = (lookupValues) => !([...new Set(lookupValues.map(obj => obj.key))].length === lookupValues.length)
console.log(isDuplicate(lookupValues))
I made a vanilla Javascript code snippet with es6 Set object.
var lookupValues = [{"key":"xiomi","value":"phone","id":1},{"key":"samsung","value":"tab",id:2},{"key":"blackberry","value":"phone","id":3},{"key":"xiomi","value":"tab","id":4},{"key":"asus","value":"phone",id:5}]
const keys = lookupValues.map((v) => v.key)
const keySetSize = new Set(keys).size
const hasDuplicate = keys.length > keySetSize
console.log(hasDuplicate)

How to find existence of an array in a set?

Since set in Javascript is able to take object, including arrays, how do I find the existence of an array list in a set?
I tried the following code:
var sello = new Set();
sello.add(["a","b"])
console.log(sello.has(["a","b"])) // outputs false
I'm assuming
sello.has(["a","b"])
should have output true since I've added the exact array in the set sello. Am I missing out some falsy truthy thing or any logical error?
Note:
I'm not looking to match only the character "a" and/or "b", I'm
looking to match the whole array ["a","b"].
I'm looking to match the array. I just need the content to be the
same, the elements doesn't have to be the same order.
What you're trying to do won't work because in Javascript you can't compare arrays like that, even if they have the same values. This is because arrays are reference types, not value types, and for reference types Javascript determines whether they are equal or not based on whether they are referencing the same object (i.e. the same place in memory). For instance, just try:
console.log(['a','b'] == ['a','b']); // false
Despite having the same values, each array is a new reference, so they are not equal to each other.
In contrast, the comparison in the code below does involve arrays referencing the same object on both sides of the equation:
let a = ['a','b'];
console.log(a == a); // true
And therefore:
let sello = new Set();
sello.add(a);
console.log(sello.has(a)); // true
To remedy this, you'll want to create a function that compares arrays based on their values. You can first check if the arrays have the same length. If not, then they're not equal. You can then loop through the items in each and see if any are different for any given position. If so, they're not equal. Otherwise, assuming you're dealing with a flat array of primitive values (no nested objects of reference type), then the arrays are equal. This is what I do in 'isEqual' below:
function isEqual(x,y) {
if (x.length != y.length)
return false;
for (let i in x)
if (x[i] != y[i])
return false;
return true;
}
Test it if you like:
console.log(isEqual(['a','b'],['a','b'])); // true
Now, unfortunately, Set.has() doesn't accept a function, so we can't use it with isEqual. But you can just loop through the values of the set. If creating a one-liner is the goal, the best way I have found to do this is to convert the set to an array and use the some method. some accepts a function that evaluates each row, and if it returns true for any row, then the result is true, else false.
console.log(
[...sello].some(item => isEqual(item, ['a','b']))
);
// true
In JavaScript, Arrays are Objects, and no two separate Objects are ever considered equal.
MDN shows the same error with a standard object:
var set1 = new Set();
var obj1 = {'key1': 1};
set1.add(obj1);
set1.has(obj1); // returns true
set1.has({'key1': 1}); // returns false because they are different object references
The easiest way to use .has with an Object (such as an Array) is to get a reference to the Object, like:
let sello = new Set();
let myArray = ["a","b"];
sello.add(myArray);
console.log(sello.has(myArray)); // outputs true
If you can't get a reference to the Array, you'll probably need to check each Array in the Set by iterating through the Array and comparing each element individually.
You could do this more concisely, but this explicit example clarifies the process:
// Declares and populates the Set
let sello = new Set();
sello.add( ["a", "c"] );
sello.add( ["a", "b"] );
sello.add( ["b", "c"] );
// Tests the `setHasArray` function
let result = setHasArray(sello, ["a", "b"]);
console.log(`result: ${result}`);
// Defines the `setHasArray` function
function setHasArray(theSet, arrayToMatch){
// Creates a flag
let isMatch = false;
// Iterates through the Set
for (let member of theSet){
// Logs the Array we're about to compare elements of
console.log("comparing:", member);
// Makes sure this member is an Array before proceeding
if(Array.isArray(member)){
// Tentatively sets the flag to `true`
isMatch = true;
// Iterates through the Array, comparing each value
arrayToMatch.forEach( (_, index) => {
// Logs the comparison for the current value
console.log(
member[index]
+ (member[index] === arrayToMatch[index] ? " === " : " !== ")
+ arrayToMatch[index]
);
// Even one non-matching element means the Array doesn't match
if(member[index] !== arrayToMatch[index]){
console.log("Rats! Looked like a possible match there for a second.");
isMatch = false;
}
});
// Logs a successful match for the current member of the Set
if(isMatch){
console.log("Found a match!")
// Stops checking Arrays lest the flag get reset and give us a false negative
break;
}
}
}
// Returns our result
return isMatch;
}
(See .forEach on MDN if you're not familiar with this method.)

Underscore how to use the each and sort multiple array of objects

I have 2 sets in an array, each of these sets is an array of objects. I'd like to sort both of them using _.each and return a sorted object with the following:
var O1 = [{'name':'one'}, {'name':'two'}, {'name':'three'}, {'name':'four'}, {'name':'five'}, {'name':'six'}];
var O2 = [{'name':'rat'}, {'name':'cat'}, {'name':'lion'}, {'name':'tiger'}, {'name':'dog'}, {'name':'horse'}];
var sortIt = [O1, O2];
_.each(sortIt, function(item){
item = _.sortBy(item, function(arr){
return arr.name;
})
return item;
})
console.log(O1, "\n", O2); //nothing changed!
... but, apparently, nothing changes. The question is, what should be the proper approach?
Live Demo
First and foremost, it's kind of useless checking the values of O1 and O2 variables after the sorting process - they won't change. See, _.sortBy doesn't order the given array in place (as native Array#sort does), instead it returns a new (sorted) copy.
Second, it makes little sense to return anything from _.each iterator function - it'll just be ignored.
Finally, to adjust the specific element of a list, you'll need to address that element; just reassigning some value to a param variable (item in your code) won't be enough.
Here's one approach to do what you want:
var sortIt = [O1, O2];
_.each(sortIt, function(item, index, list) {
list[index] = _.sortBy(item, function(arr) {
return arr.name;
});
})
console.log(sortIt); // something is definitely changed now!
Demo.

Categories