Lodash. Smart merge two objects by keys - javascript

I have the two objects. A and B.
A
{
"beta" : {
"value": null,
"error" : null
},
"hamma" : {
"value": null,
"error" : null
},
"zerta" : {
"value": null,
"error" : null
},
"mozes" : 5
}
B
{
"beta" : 5,
"hamma" : 2
}
How do I can loop through the A keys, compare it with the B object and update the values of the existing keys in the A object via Lodash? Maybe there is exists some nice way? I tried to use "assing, assignWith" but looks like I haven't understood how it works.
The result should looks like that:
{
"beta" : {
"value": 5,
"error" : null
},
"hamma" : {
"value": 2,
"error" : null
},
"zerta" : {
"value": null,
"error" : null
},
"mozes" : 5
}
Thanks for any information.
I have resolved this solution via native js by that way but I want to know how can I do it via Lodash.
export function mapServerModelToStateValues(state, serverModel) {
let updatedState = {};
const serverModelKeyList = Object.keys(serverModel);
Object.keys(state).forEach(stateKey => {
serverModelKeyList.forEach(modelKey => {
if ( modelKey === stateKey ) {
updatedState[ stateKey ] = {
...state[ stateKey ],
value : serverModel[ modelKey ]
}
}
});
});
console.log(updatedState);
}

You can use _.mergeWith lodash method and pass custom function.
var a = {"beta":{"value":null,"error":null},"hamma":{"value":null,"error":null},"zerta":{"value":null,"error":null},"mozes":5}
var b = {"beta":5,"hamma":2, "mozes": 123}
_.mergeWith(a, b, function(aValue, bValue) {
_.isPlainObject(aValue) ? aValue.value = bValue : aValue = bValue
return aValue
})
console.log(a)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Here's a solution that iterates over the B array and uses set to update the value:
_.each(updates, (value, key) => _.set(data, `${key}.value`, value))

This will do the trick, notice that the result will have all the keys in the same value, error format
const A = {
"beta": {
"value": null,
"error": null
},
"hamma": {
"value": null,
"error": null
},
"zerta": {
"value": null,
"error": null
},
"mozes": 5
}
const B = {
"beta": 5,
"hamma": 2
}
const C = _.mapValues(A, (value, key) => {
return {
...value,
value: B[key] || value.value
}
});
console.log(C)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Map through the _keys from your second object to update the first object accordingly:
// obj a
const a = {
beta: {
value: null,
error: null
},
hamma: {
value: null,
error: null
},
zerta: {
value: null,
error: null
},
mozes: 5
};
// obj b
const b = {
beta: 5,
hamma: 2
};
// map through the 'obj b' keys and update 'obj a' accordingly
_.keys(b).map(key => {
a[key].value = b[key];
});
// log obj a to the console
console.log(a);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Update: I would use the solution from #GruffBunny - the idea is similar to this one, but done much more elegantly using lodash.

You can use lodash#merge and lodash#mapValues to achieve this.
var result = _.merge({}, a, _.mapValues(b, value => ({ value })));
var a = {
"beta" : {
"value": null,
"error" : null
},
"hamma" : {
"value": null,
"error" : null
},
"zerta" : {
"value": null,
"error" : null
},
"mozes" : 5
};
var b = {
"beta" : 5,
"hamma" : 2
};
var result = _.merge({}, a, _.mapValues(b, value => ({ value })));
console.log(result);
.as-console-wrapper { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Related

Having issues with deleting object from an array where match is found

I have the follow function that will delete object from array. It also returns the array tree without the items that was deleted. My issues is that it works when my objToFindBy is null deleting everything where {group: null} is found however it error with promise rejection if I set objToFindBy {group: 'some string'}
This code should delete all occurrences where the objToFindBy is a match, example {group: null} will find everywhere will the group is null and delete all object and then return the full tree without the objects that was deleted
findAndDeleteAll(tree, 'items', {group: null}) // work and delete all where match. then returns the tree without deleted objects
findAndDeleteAll(tree, 'items', {group: 'd575c91f-4765-4073-a948-5e305116610c'}) // promise rejection
const tree ={
"type": "app",
"info": "Custom Layout",
"items": [
{
"id": "d575c91f-4765-4073-a948-5e305116610c",
"title": "Fc",
"group": null
},
{
"id": "890d5a1e-3f03-42cd-a695-64a17b6b9bea",
"title": null,
"group": null
},
{
"id": "cbe00537-0bb8-4837-8019-de48cb04edd6",
"title": null,
"group": "d575c91f-4765-4073-a948-5e305116610c",
},
{
"id": "b8751c32-2121-4907-a229-95e3e49bcb39",
"title": null,
"group": "d575c91f-4765-4073-a948-5e305116610c"
}
],
"Children": []
}
var findAndDeleteAll = function findAndDeleteAll(tree, childrenKey, objToFindBy) {
var treeModified = false;
var findKeys = Object.keys(objToFindBy);
var findSuccess = false;
findKeys.forEach(function (key) {
(0, _lodash2.default)(tree[key], objToFindBy[key]) ? findSuccess = true : findSuccess = false;
});
if (findSuccess) {
Object.keys(tree).forEach(function (key) {
return delete tree[key];
});
return tree;
}
function innerFunc(tree, childrenKey, objToFindBy) {
if (tree[childrenKey]) {
var _loop = function _loop(index) {
var findKeys = Object.keys(objToFindBy);
var findSuccess = false;
findKeys.forEach(function (key) {
(0, _lodash2.default)(tree[childrenKey][index][key], objToFindBy[key]) ? findSuccess = true : findSuccess = false;
});
if (findSuccess) {
tree[childrenKey].splice(index, 1);
treeModified = true;
}
if (tree[childrenKey][index].hasOwnProperty(childrenKey)) {
innerFunc(tree[childrenKey][index], childrenKey, objToFindBy);
}
};
for (var index = tree[childrenKey].length - 1; index >= 0; index--) {
_loop(index);
}
}
}
innerFunc(tree, childrenKey, objToFindBy);
return treeModified ? tree : false;
};
how about shorter solution?
const findAndDeleteAll = (tree, childrenKey, nestedKey, nestedValue) => {
return{...tree, [childrenKey]: tree[childrenKey].filter((row) => {
return row[nestedKey] !== nestedValue;
})}
}
const a = findAndDeleteAll(tree, 'items', 'group', null) // work and delete all where match. then returns the tree without deleted objects
const b = findAndDeleteAll(tree, 'items', 'group', 'd575c91f-4765-4073-a948-5e305116610c') // promise rejection
console.warn(a);
console.warn(b);
Your function would be so much simper, reusable, better, if you send not the redundant tree - but instead deleteFrom(tree.items, "group", null);. think about it.
const deleteFrom = (arr, pr, val) => arr.filter(ob => ob[pr] !== val);
const tree = {
type: "app",
info: "Custom Layout",
items: [
{ id: "10c", title: "Fc", group: null },
{ id: "bea", title: null, group: null },
{ id: "dd6", title: null, group: "10c" },
{ id: "b39", title: null, group: "10c" },
],
Children: []
};
const items = deleteFrom(tree.items, "group", null);
console.log(items); // Only the filtered items array
const newTree = {...tree, items};
console.log(newTree); // Your brand new tree!

Complex filter between 2 objects and a boolean

I have this array burgerActions :
[
{
statusId: 2,
label: 'Accept'
},
{
statusId: 3,
label: 'Reject'
},
{
label: 'Consult'
},
{
label: 'Transfer'
}
]
and this object status which can be either :
{
"label": "Accept",
"id": 2
}
or :
{
"label": "Reject",
"id": 3
}
In a first case you have to create a new array from burgerActions array where the statusId is not equivalent to the id of the status object that we have (we can only have one status object of the 2 cases that I listed).
For that I used the filter method :
const result = burgerActions.filter((element) => {
return element.statusId !== recommendation.status.id
})
In the second case I need a complex conditioning adding with boolean
const statusRef = recommendation.recipient
In a first case I want if statusRef is false filter the last object in the burgerAction ({label: 'Transfer'}) but not in the case if statusRef is true.
I need a method that does this type of filter without using the if () conditions because there are several cases to handle.
If you want to filter the objects that doesn't have the same statusId as in the recommendation.status.id and if recommendation.recipient === true filter the ones that doesn't have statusId, you can use this condition in the filter callback function:
element.statusId !== recommendation.status.id && recommendation.recipient ? element.statusId != null : true;
Where && recommendation.recipient ? element.statusId != null : true means that if recommendation.recipient is true filter elements with a statusId.
Here's how should be your code:
var recommendation = {
status: {
"label": "Pending",
"id": 1
},
recipient: true
};
const result = burgerActions.filter((element) => {
return element.statusId !== recommendation.status.id && recommendation.recipient ? element.statusId != null : true;
});
Demo:
var burgerActions = [{
statusId: 2,
label: 'Accept'
},
{
statusId: 3,
label: 'Reject'
},
{
label: 'Consult'
},
{
statusId: 1,
label: 'Transfer'
}
];
var recommendation = {
status: {
"label": "Pending",
"id": 1
},
recipient: true
};
const result = burgerActions.filter((element) => {
return element.statusId !== recommendation.status.id && recommendation.recipient ? element.statusId != null : true;
});
console.log(result);

Pure JavaScript JSON compare array

I have to compare some JSON data and return index of position. I use pure JavaScript.
I have data below:
NAMES
[
{
"someName" : Name1,
"secondData" : "aaaa1",
"thirdData" : bbbb1
},
{
"someName" : Name2,
"secondData" : "aaaa2",
"thirdData" : bbbb2
},
{
"someName" : Name3,
"secondData" : "aaaa3",
"thirdData" : bbbb3
},
{
"someName" : Name4,
"secondData" : "aaaa4",
"thirdData" : bbbb4
}
]
and JSON SEATS
[
{
"seats" : 0,
"someName" : "Name4",
omeData" : null,
"someData" : null
},
{
"seats" : 1,
"someName" : "Name3",
"someData" : null,
"someData" : null
},
{
"seats" : 2,
"someName" : "Name1",
"someData" : null,
"someData" : null
},
{
"seats" : 3,
"someName" : "Name2",
"someData" : null,
"someData" : null
}
]
All what I want to do is compare this JSON like this:
Take someName from NAMES.someName and search the same name in SEATS.someName if is the same create new array RESULTS. Index in RESULTS array shuldbe SEATS.seats and data from NAMES.
Example below
RESULTS[0] = NAMES[{"someName" : Name4,"secondData" : "aaaa4","thirdData" : bbbb4}]
RESULTS[1] = NAMES[{"someName" : Name3,"secondData" : "aaaa3","thirdData" : bbbb3}]
RESULTS[2] = NAMES[{"someName" : Name1,"secondData" : "aaaa1","thirdData" : bbbb1}]
RESULTS[3] = NAMES[{"someName" : Name2,"secondData" : "aaaa2","thirdData" : bbbb2}]
I start do this like this but I stack
for(i=0;i<=459; i++) {
if(mergeData[i][2] == jsonData[4].rows[i].find(compareElement)) {
}
}
function compareElement(element) {
return element.someName == i;
}
Problem is if I use find like this I have some error and program stop I can't find way how to solve this.
var result = [];
NAMES.forEach(function(name) {
var found = SEATS.find(function(seat) {
return name.someName === seat.someName
});
if (found) {
result[found.seats] = name;
}
});
This solution works for both Objects as well as Arrays.
function compare(obj: any, obj2: any): boolean {
if (typeof obj !== typeof obj2) {
return false;
}
if (typeof obj !== "object" && typeof obj2 !== "object") {
return obj === obj2;
} else {
for (let key in obj) {
if (key) {
return compare(obj[key], obj2[key]);
}
}
return false;
}
}

Refactoring object into a flat array

I have an object like this.
{Brunch: 2, Kimchi: 1}
I need to refactor it into an an array/object
[{
"label" : "Brunch",
"value" : 2
},
{
"label" : "Kimchi",
"value" : 1
}]
You can use Object.keys() and map() to get desired result.
var obj = {
Brunch: 2,
Kimchi: 1
}
var result = Object.keys(obj).map(function(k) {
return {
"label": k,
"value": obj[k]
}
})
console.log(result)
The simplest way:
var result = Object.keys(input).map(key => ({
label: key,
value: input[key],
}));

Check if there are null values in an array of objects

I have this array of objects.
[Object, Object, Object]
0:Object
name: "Rick"
Contact: "Yes"
Date:'null'
Location:'null'
1:Object
name:"Anjie"
Contact:"No"
Date:'13/6/2016'
Location:'LA'
2:Object
name:"dillan"
Contact:"Maybe"
Date:'17/6/2016'
Location:'NY'
As you can see, there are null values for Object[0] for Date and Location. I want to check if there is a null value present in the entire array of Objects.
If there is a null value present for 'Date' and 'Location', i should be able to display 'Null present' at the console. If no null values are present, it should display 'Data right' at the console.
can someone please let me know how to achieve this.
var wasNull = false;
for(var i in objectsArray) {
if(objectsArray[i].Date == null || objectsArray[i].Location == null) wasNull = true;
}
if(wasNull) console.log('Was null');
else console.log('Data right');
Do it using Object.keys() and Array#some methods
var data = [{
name: "Rick",
Contact: "Yes",
Date: null,
Location: null
}, {
name: "Anjie",
Contact: "No",
Date: '13/6/2016',
Location: 'LA'
}, {
name: "dillan",
Contact: "Maybe",
Date: '17/6/2016',
Location: 'NY'
}];
// iterate over array elements
data.forEach(function(v, i) {
if (
// get all properties and check any of it's value is null
Object.keys(v).some(function(k) {
return v[k] == null;
})
)
console.log('null value present', i);
else
console.log('data right', i);
});
Use some() and check if there is a null.
var arr = [
{ a : "a", b : "b", c : "c" },
{ a : "a", b : "b", c : "c" },
{ a : "a", b : "b", c : null }
];
function hasNull(element, index, array) {
return element.a===null || element.b===null || element.c===null;
}
console.log( arr.some(hasNull) );
If you do not want to hardCode the if, than you need to add another loop and loop over the keys.
var arr = [
{ a : "a1", b : "b1", c : "c1" },
{ a : "a2", b : "b2", c : "c2" },
{ a : "a3", b : "b3", c : null }
];
function hasNull(element, index, array) {
return Object.keys(element).some(
function (key) {
return element[key]===null;
}
);
}
console.log( arr.some(hasNull) );
or JSON with a reg exp (
var arr = [
{ a : "a1", b : "b1", c : "c1" },
{ a : "a2", b : "b2", c : "c2" },
{ a : "a3", b : "b3", c : null }
];
var hasMatch = JSON.stringify(arr).match(/:null[\},]/)!==null;
console.log(hasMatch);
A solution using underscore:
var nullPresent = _.some(data, item => _.some(_.pick(item, 'Date', 'Location'), _.isNull));

Categories

Resources