How to merge objects using JavaScript? - javascript

I have the below
$scope.Marketing = [{
'ProductId':1,
'ProductName':'Product 1',
'ProductDescription':'Product Description 1'
},
{
'ProductId':2,
'ProductName':'Product 2',
'ProductDescription':'Product Description 2'
}];
$scope.Finance=[{
'ProductId':1,
'Price':'$200.00'
},
{
'ProductId':2,
'Price':'$100.00'
}];
$scope.Inventory=[{
'ProductId':1,
'StockinHand:':26
},
{
'ProductId':2,
'StockinHand':40
}];
I want the output to be
My Merge function is here
$scope.tempresult=merge($scope.Marketing,$scope.Finance);
$scope.result=merge($scope.tempresult,$scope.Inventory);
function merge(obj1,obj2){ // Our merge function
var result = {}; // return result
for(var i in obj1){ // for every property in obj1
if((i in obj2) && (typeof obj1[i] === "object") && (i !== null)){
result[i] = merge(obj1[i],obj2[i]); // if it's an object, merge
}else{
result[i] = obj1[i]; // add it to result
}
}
for(i in obj2){ // add the remaining properties from object 2
if(i in result){ //conflict
continue;
}
result[i] = obj2[i];
}
return result;
}
But the output is
The value for first Stock In Hand is missing.
What is the mistake I am making?
Edit

you could use Jquery.extend property, have a look at the plnkr code
$scope.result=merge($scope.Marketing, $scope.Finance,$scope.Inventory);
function merge(obj1,obj2, obj3){
return $.extend(true, obj1,obj2,obj3)
}
};
http://plnkr.co/edit/gKQ9bc?p=preview

One approach is populating the one array of products with missing properties from the other two (after matching with product id).
See: http://jsfiddle.net/zekbxh90/1/ - and check the console output
Code:
var a = [{
'ProductId': 1,
'ProductName': 'Product 1',
'ProductDescription': 'Product Description 1'
}, {
'ProductId': 2,
'ProductName': 'Product 2',
'ProductDescription': 'Product Description 2'
}];
var b = [{
'ProductId': 1,
'Price': '$200.00'
}, {
'ProductId': 2,
'Price': '$100.00'
}];
var c = [{
'ProductId': 1,
'StockinHand:': 26
}, {
'ProductId': 2,
'StockinHand': 40
}];
// lets add the props from b abd c into a to get the desired result
a.forEach(function (_itemA) {
// get product id in a
var productId = _itemA.ProductId,
matching = false,
prop = false;
// get the matching item in b and add new props to a
b.forEach(function (_itemB) {
if (_itemB.ProductId === productId) merge(_itemA, _itemB);
});
// get the matching item in c and add new props to a
c.forEach(function (_itemC) {
if (_itemC.ProductId === productId) merge(_itemA, _itemC);
});
});
console.log(a);
function merge(_to, _from) {
for (var prop in _from) {
if (!_to.hasOwnProperty(prop) && _from.hasOwnProperty(prop)) _to[prop] = _from[prop];
}
}

Related

Use array find() method instead of for loop

How can we use Array.find() method instead of for loop in this code ?
onLoadTickets() {
const ticketsReq = this.ticketService.getTickets();
const tariffsReq = this.tariffService.getTariffs();
forkJoin([ticketsReq, tariffsReq]).subscribe(results => {
const data = results[0];
const tariffResp = results[1];
this.tickets = data.requests;
for (let i = 0; i < this.tickets.length; i++) {
for (let j = 0; j < tariffResp.tariffs?.length; j++) {
if (tariffResp.tariffs[j].id == this.tickets[i].tariffId) {
this.tickets[i].tariff = tariffResp.tariffs[j]
}
}
}
});
}
Note :
Using find() method is not mandatory. I have to write this code with any array methods.
Edit :
I have used map() and includes() methods. my solution:
const tariffIds = tariffResp.tariffs.map((tariff: Tariffs) => tariff.id);
this.tickets.map((item) => {
if (tariffResp.tariffs === null || tariffResp.tariffs === undefined) {
return item;
}
if (tariffIds.includes(item.tariffId)) {
item.tariff = tariffResp.tariffs[tariffIds.indexOf(item.tariffId)];
}
return item;
});
This works but I'm not sure it's the best solution
Array.find() method returns the first element in the provided array that satisfies the provided testing function.
So, if in your case you only have one tariff against all the tickets then you can go ahead with Array.find() but if you have multiple tariff and multiple tickets then you can go ahead with Array.filter().
Demo with Array.find() :
const tickets = [{
tariffId: 1,
name: 'Ticket 1'
}, {
tariffId: 2,
name: 'Ticket 2'
}];
const tariffResp = {
tariffs: [{
id: 1
}]
};
const result = tickets.find((obj) => tariffResp.tariffs[0].id);
console.log(result);
Demo with Array.map() along with Array.filter() :
const tickets = [{
tariffId: 1,
name: 'Ticket 1'
}, {
tariffId: 2,
name: 'Ticket 2'
}, {
tariffId: 3,
name: 'Ticket 3'
}];
const tariffResp = {
tariffs: [{
id: 1
}, {
id: 2
}]
};
const result = tariffResp.tariffs.map((obj) => {
return tickets.filter((ticketObj) => obj.id === ticketObj.tariffId);
});
console.log(result);
this.tickets=data.request.map(x=>{
const obj:any=x;
obj.tariff=tariffResp.find(t=>t.id==x.tariffId)
return obj
})
You loop over data.request using map. map transform an array in another
First you create an object with the values of x
After you add a new propety "tariff" that is the "tariffResp" who has the "id" property equal to the property "tariffId" of x
Check find and map methods of an array

Looping through (possibly infinitely) repeating object structure

I have a problem I can't get my head around. If I am looking for an object with a certain ID in a possibly infinite data structure, how can I loop through it until I find the object I need and return that object?
If this is what my data looks like, how can I get the object with id === 3 ?
{
id: 0,
categories: [
{
id: 1,
categories: [
{
id: 2,
categories: [ ... ]
},
{
id: 3,
categories: [ ... ]
},
{
id: 4,
categories: [ ... ]
},
]
}
]
}
I tried the following:
findCategory = (categoryID, notesCategory) => {
if (notesCategory.id === categoryID) {
return notesCategory;
}
for (let i = 0; i < notesCategory.categories.length; i += 1) {
return findCategory(categoryID, notesCategory.categories[i]);
}
return null;
};
But that doesn't get ever get to id === 3. It checks the object with id: 2 and then returns null. It never gets to the object with id: 3.
Here is a JSbin: https://jsbin.com/roloqedeya/1/edit?js,console
Here is the case. when you go in to the first iteration of 'for' loop, because of the return call, the execution is go out from the function. you can check it by using an console.log to print the current object in the begin of your function.
try this
function find(obj, id) {
if(obj.id === id) {
console.log(obj) // just for testing. you can remove this line
return obj
} else {
for(var i = 0; i < obj.categories.length; i++) {
var res = find(obj.categories[i], id);
if(res) return res;
}
}
}
hope this will help you. thanks
You need to store the intermediate result and return only of the object is found.
function findCategory(object, id) {
var temp;
if (object.id === id) {
return object;
}
object.categories.some(o => temp = findCategory(o, id));
return temp;
}
var data = { id: 0, categories: [{ id: 1, categories: [{ id: 2, categories: [] }, { id: 3, categories: [] }, { id: 4, categories: [] }] }] }
result = findCategory(data, 3);
console.log(result);

angularjs: check if value exists in array of objects

var a = [ { id:1}, {id:2} ];
var b = {id:1};
var res = a.indexOf(b._id) == -1;
console.log(res);
I want to check if b._id is in a[].
Note: a[] is an array of objects
Try this..
var a = [{ id:1}, {id:2}];
var b={id:1};
var arrayWithIds = a.map(function(x){
return x.id
}); // get new array contains all ids
var present = arrayWithIds.indexOf(b.id) != -1 // find the b.id array
console.log(present);
Here is the reference for Map and indexOf
This should work :
var a = [ { id:1} ,{id:2} ];
var b={id:1}
console.log(a.findIndex(function(obj){return obj.id=b.id}))
indexOf works when you are dealing with indexed arrays not with array of objects.
Please use the following code:
var a = [ { id:1}, {id:2} ];
var b={id:1}
function findMatch(element) {
return element.id === b.id;
}
console.log(a.findIndex(findMatch));
A better way is using .find function.
let a = [{
id: 1
}, {
id: 2
}],
b = {
id: 1
},
obj = a.find(function(itm) {
return itm.id == b.id;
});
console.log(obj)
And also using .findIndex function to get just index of item in array.
let a = [{
id: 1
}, {
id: 2
}],
b = {
id: 1
},
objIndex = a.findIndex(function(itm) {
return itm.id == b.id;
});
console.log(objIndex)
And for getting all objects with that condition use .filter function.
let a = [{
id: 1
}, {
id: 2
}],
b = {
id: 1
},
objArr = a.filter(function(itm) {
return itm.id == b.id;
});
console.log(objArr)
Array.map() function compare id and its value and return a Boolean value if map as commented by #Slava Utesinov
var a = [{id: 1}, {id: 2}];
var b = {id: 1};
if(a.map(x => x.id).indexOf(b.id) != -1){
console.log("Exists");
}else{
console.log("Not exists");
}
try this
var a = [ { id:1} ,{id:2} ];
var b={id:1}
console.log(a.find(x=>x.id==b.id))// return matched record
var a = [ { id:1} ,{id:2} ];
var b={id:3}
console.log(a.find(x=>x.id==b.id)) //return undefined
Use Array.map() function of JavaScript to check it. It will compare id and its value as well.
Below is working code:
var a = [{
id: 1
}, {
id: 2
}];
var b = {
id: 1
};
if (a.map(x => x.id).indexOf(b.id) != -1) {
console.log("Available");
} else {
console.log("Not available");
}
You can use Filter of AngularJS
var a = [{id:1}, {id:2}];
var b = {id:1};
var found = false;
var filterResult = $filter('filter')(a, {id: b.id}, true);
if (filterResult.length > 0) {
found = true;
}

How do i filter array of objects nested in property of array objects?

I have model like this:
var model = [{id: 1, prices: [{count: 2}, {count: 3}]}, {id: 2, prices: [{count: 2}]}, {id: 3, prices: [{count: 3}]}];
and I need to filter this objects of array useing property count and I will need to return matched objects in three scenarios:
if the objects have two objects in array prices,
if the objects have one object in array prices matching count:2,
if the objects have one property in array prices matching count:3.
so..when i click the button without assigned value i wanna see all objects, when i click button with value = 2 i wanna see objects with count: 2 and when i click the button with value = 3 i wanna get objects with count: 3, i must do this in AngularJS –
maybe something like this?
var result = model.filter(function(m) {
// make sure the m.prices field exists and is an array
if (!m.prices || !Array.isArray(m.prices)) {
return false;
}
var numOfPrices = m.prices.length
if (numOfPrices === 2) { // return true if its length is 2
return true;
}
for (var i = 0; i < numOfPrices; i++) {
if (m.prices[i].count &&
(m.prices[i].count === 2 ||
m.prices[i].count == 3)) {
return true;
}
}
return false;
});
use lodash or underscore library.. and then your code with lodash will be like:
_.filter(model, function(i){
return _.intersection(_.map(i.prices, 'count'), [3,2]).length;
})
it returns items that on their price property have array which contains element with count = 3 or count = 2
var model = [{
id: 1,
prices: [{
count: 2
}, {
count: 3
}]
}, {
id: 2,
prices: [{
count: 2
}]
}, {
id: 3,
prices: [{
count: 3
}]
}];
var search = function(data) {
var result = {};
function arrayObjectIndexOf(myArray, searchTerm, property) {
for (var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i][property] === searchTerm) return i;
}
return -1;
}
for (var index in data) {
if (data[index].hasOwnProperty("prices") && arrayObjectIndexOf(data[index].prices, 2, 'count') != -1) {
result[data[index].id] = data[index];
} else if (data[index].hasOwnProperty("prices") && arrayObjectIndexOf(data[index].prices, 3, 'count') != -1) {
result[data[index].id] = data[index];
} else if (data[index].hasOwnProperty("prices") &&
data[index].prices.length == 2) {
result[data[index].id] = data[index];
}
}
return result;
}
var output = search(model);
console.log(output);

How to change a value of an object and push the object back to its array?

I have an array of objects that looks like this:
arr: [
{
id: '1',
dataX: ''
},
{
id: '2',
dataX: ''
}
]
I want to loop through each object and assign them a new value for dataX. The new value can be fetched like this
_.each(arr, el => {
if (el.id === target.id) {
console.log(target.x)
// => new value that should be assigned to the corresponding object
}
Now, how can I push that new x value into the corresponding object (or push the new object to the corresponding position)? Say, if el.id === 1, push the new x to the dataX of the object with id 1?
(Lodash solutions are welcomed.)
Lodash be gone! :D
var json = [
{ id: '1', dataX: '' },
{ id: '2', dataX: '' }
]
var target = {id: '2', x: 'X GONE GIVE IT TO YA!'} // Dummy data
// Note: map() returns a new array hence the json = json
json = json.map(item => {
if (item.id === target.id) {
item.dataX = target.x
}
return item
})
console.log(json)
// If you want to modify the original array of objects
json.forEach(item => {
if (item.id === target.id) {
item.dataX = target.x
}
})
console.log(json)
Plunker
var arr =[ { id: '1', dataX: '' }, { id: '2', dataX: '' }];
console.log(arr[0]);
console.log(arr[1]);
var datas = '5';
var bonus = 'More data can be placed into the item';
for(var i = 0; i < arr.length; i++){
arr[i].dataX = datas; //modifies the actual item in the array
arr[i].dataY = bonus; //javaScript!
}
console.log(arr[0]);
console.log(arr[1]);
By addressing the actual item in the array you do not have to push it back in. It's changed. The answer above creates a new array in place of the existing one, and remaps all the items there in.
If that is the desired result then the question is poorly phrased.

Categories