In Javascript (ES6) have two objects with data.
const template = {
a: '',
b: '',
x: ''
}
This is the data object I will receive
const data = {
a: 'test',
b: 'test',
c: 'test'
}
How can I map the data from my received object to my template object without allowing values that are not present in the template object.
So the result should be this.
const result = {
a: 'test',
b: 'test',
x: ''
}
you can use a for...in loop :
const template = {
a: '',
b: ''
}
const data = {
a: 'test',
b: 'test',
c: 'test'
}
const result = {};
for (let k in template) {
result[k] = data[k];
}
console.log(result)
You could get the template object and the properties with the same keys from data.
const
template = { a: '', b: '', x: '' },
data = { a: 'test', b: 'test', c: 'test' },
result = Object.assign(
{},
template,
...Object.keys(template).map(k => k in data && { [k]: data[k] })
);
console.log(result);
Something like this:
let result = {};
const template = {
a: '',
b: ''
}
const data = {
a: 'test',
b: 'test',
c: 'test'
}
for (let prop in data) {
if(prop in template) result[prop] = data[prop];
}
console.log(result);
Just for fun you could use some Proxy magic :)
const template = {
a: '',
b: ''
}
const data = {
a: 'test',
b: 'test',
c: 'test'
}
const result = { ...new Proxy(data, {
ownKeys: () => Object.keys(template)
})
}
console.log(result)
const template = {
a: '',
b: ''
}
const data = {
a: 'test',
b: 'test',
c: 'test'
}
function setData(inputTemplate, inputData) {
outputObject = {}
for (var key in inputTemplate) {
if (inputData[key]) {
outputObject[key] = inputData[key];
}
}
return outputObject
}
console.log(setData(template, data))
You can use of Array.reduce to look at your object and only change the keys you are interested in. This method will also handle the case where the key you want to copy from data is not here. Also we have created a new object, we do not mutate the existing one.
Without mutation (new object)
const template = {
a: '',
b: '',
};
const data = {
a: 'test',
b: 'test',
c: 'test',
};
const ret = Object.keys(template).reduce((tmp, x) => {
tmp[x] = data[x] !== void 0 ? data[x] : tmp[x];
return tmp;
}, {
...template,
});
console.log(ret);
Mutating the object (use the old object)
const template = {
a: '',
b: '',
};
const data = {
a: 'test',
b: 'test',
c: 'test',
};
Object.keys(template).forEach((x) => {
template[x] = data[x] !== void 0 ? data[x] : template[x];
});
console.log(template);
You can simply loop on the keys of your template, and set the value with the data object with the same key.
const data = {
a: 'test',
b: 'test',
c: 'test'
}
const template = {
a: '',
b: ''
}
Object.keys(template).forEach((key) => template[key] = data[key])
console.log(template)
you can also use reduce
Example :
const template = {
a: '',
b: ''
}
const data = {
a: 'test',
b: 'test',
c: 'test'
}
const res = Object.keys(template).reduce((all, acc) => {
all[acc] = data[acc]
return all
}, {})
console.log(res)
Related
Given an array of objects all with the same property names, with javascript how would you create a new object made up of key:value pairs that are found in all the objects of the array?
For example, given:
[
{
a: 'foo',
b: 'bar',
c: 'zip'
},
{
a: 'urg',
b: 'bar',
c: 'zip'
},
{
a: 'foo',
b: 'bar',
c: 'zip'
}
]
Result:
{
b: 'bar',
c: 'zip'
}
Start with all the elements of the first item (cloned, because we don't want to change the original data), then remove any key-value pairs that do not show up in the subsequent items:
const data = [
{
a: 'foo',
b: 'bar',
c: 'zip'
},
{
a: 'urg',
b: 'bar',
c: 'zip'
},
{
a: 'foo',
b: 'bar',
c: 'zip'
}
];
const [first, ...rest] = data;
const result = rest.reduce((a, e) => {
Object.keys(a).forEach(k => {
if (!k in e || e[k] !== a[k]) {
delete a[k];
}
});
return a;
}, {...first});
console.log(result);
Just compare each value in the first object with every other object.
const [first, ...others] = [
{
a: 'foo',
b: 'bar',
c: 'zip'
},
{
a: 'urg',
b: 'bar',
c: 'zip'
},
{
a: 'foo',
b: 'bar',
c: 'zip'
}
];
for (const [key, value] of Object.entries(first)) {
for (const object of others) {
if (object[key] !== value) {
delete first[key];
}
}
}
console.log(first);
I have this object:
const data = {
a: 'name',
b: 'age',
c: 'age',
d: 'age',
e: 'name',
f: 'age'
}
and I want to group by values so I would like to have:
const result = {
name: ['a', 'e'],
age: ['b', 'c', 'd', 'f']
}
Is there a smart way to do that?
Tersest version, thanks Nick for the comma operator to save the curlies
const data = { a: 'name', b: 'age', c: 'age', d: 'age', e: 'name', f: 'age' },
arr = Object.entries(data)
.reduce((acc, [key,value]) => ((acc[value] ??=[]).push(key), acc),{});
console.log(arr)
Explanations since this is interesting to add to one's arsenal
(acc, // accumulator defined by the {} at the end of the statement
[key,value] // destructing the entries
) =>
( // bracket to set up the comma operator later
(acc[value] ??=[]) // nullish coalescing assignment - if no acc[value] then assign an array
.push(key)
, acc) // comma operator returns what is after the comma
,{});
You can iterate over all the keys and check if the corresponding value has been already assigned as key to your result object; if so, push the key into the array, if not initialise it as an array.
Something like this will work:
const data = { a: 'name', b: 'age', c: 'age', d: 'age', e: 'name', f: 'age' }
const output = {};
Object.keys(data).forEach(key => {
if (!output[data[key]]) {
// new key: assign it as a 1 element array
output[data[key]] = [key];
} else {
// existing key: push it into the array
output[data[key]].push(key);
}
});
console.log(output);
Some good solutions added, but could be more clear with Object.entries ?
const data = { a: 'name', b: 'age', c: 'age', d: 'age', e: 'name', f: 'age' }
const results = {};
Object.entries(data).forEach(([key, value]) => {
if (results[value]) {
results[value].push(key);
} else {
results[value] = [key];
}
});
console.log(results)
One way to do so:
const map = new Map;
Object.keys(data).forEach(key => {
const value = data[key];
if (!map.has(value))
map.set(value, []);
map.get(value).push(key);
});
const result = {};
map.forEach((key, value) => {
result[value] = key;
});
console.log(result);
Another way:
const data = { a: 'name', b: 'age', c: 'age', d: 'age', e: 'name', f: 'age' }
const newData = {};
Object.entries(data).forEach(pair => {
const [key, value] = pair;
if (!newData[value])
newData[value] = [];
newData[value].push(key)
});
console.log(newData)
I'm working on a project where I get an object in input like this one :
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
and I need to create some variables to get to this output :
const a = "somestring"
const b = 42
const c.d = "foo"
const c.e = "bar"
const f[0] = 1
const f[1] = 2
I got a result with this code :
for (const [k1, v1] of Object.entries(obj)) {
if (typeof v1 === "object") {
if (Array.isArray(v1)) {
for (const [k2, v2] of Object.entries(v1)) {
console.log(`const ${k1}[${k2}] = ${v2}`);
}
} else {
for (const [k2, v2] of Object.entries(v1)) {
console.log(`const ${k1}.${k2} = ${v2}`);
}
}
} else {
console.log(`const ${k1} = ${v1}`);
}
}
But when I get an object more complex like this one :
const obj = {
a: [
{
b: 'lorem'
},
{
c: 'ipsum'
}
],
d: {
e: {
f : 'foobar'
}
}
};
My output look like this :
const a[0] = [object Object]
const a[1] = [object Object]
const d.e = [object Object]
I can't find any relevant solutions. Is there a solution or npm package for this?
There is a feature called destructuring docs click here
This feature as the docs say will help you create new variables from a nested object.
Taking a object which is nested you can access its leaf values and assign them directly to vars like this:
const o = {
a: 'a',
b: {
c : 'c',
d: {
e: 'e'
}
}
};
const {a ,b : { c, d: {e} }} = o;
alert(a);
alert(c);
alert(e);
Edit: it works with arrays as well not objects only
You can do it with eval function in JS:
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
var log = console.log;
for (let key in obj) {
//log(key);
eval(`var ${key} = obj.${key}`);
}
log(a);
log(b);
log(c);
log(f);
I think you want something like this:
const obj = {
a: 'somestring',
b: 42,
c: {
d: 'foo',
e: 'bar'
},
f: [1, 2]
};
const parse = (obj, prefix = '', isArray=false) => {
Object.entries(obj).forEach(([k, v]) => {
if (typeof v === 'object') parse(v, `${k}`, Array.isArray(v))
else {
const value = (typeof v === 'string') ? `"${v}"` : v;
const before = isArray ? '[' : prefix ? '.' : '';
const after = isArray ? ']' : '';
console.log(`const ${prefix}${before}${k}${after} = ${value}`)
}
});
}
parse(obj);
What is simpler pattern to avoid updating inputs if one of the keys is empty in payload ?
Is there a nice ES6 syntax ?
const master = {
inputs: {a: [], b: [], c: []}
};
const {a, b, c} = payload;
const updateMaster = (payload) => ({
...master, inputs: {...master.inputs, ...payload}
});
To filter the fields of an object, use Object.entries to retrieve the fields, Array.prototype.filter to filter then, and Object.formEntries to reconstruct an object from the filtered entries.
let payload = {
a: [],
b: [1, 2]
};
let nonEmptyPayload = Object.fromEntries(Object.entries(payload).filter(([_, v]) => v.length))
console.log(nonEmptyPayload);
Applying this to your example,
let master = {
inputs: {
a: [],
b: [13, 14],
c: [10, 12]
}
};
let trimObj = obj => Object.fromEntries(Object.entries(obj).filter(([_, v]) => v.length));
let updateMaster = payload => ({
...master,
inputs: { ...master.inputs,
...trimObj(payload)
}
});
updateMaster({
b: [15, 16], // Will override master.c
c: [] // Will not override master.c
});
console.log(master);
You could create a function like this. It removes all empty values from an object, without directly modifying the object passed to the function.
const removeEmpty = obj => {
return Object.keys(obj).reduce((acc, key) => {
// value is "falsey" or is empty array
return !obj[key] || (Array.isArray(obj[key]) && !obj[key].length)
? acc
: {...acc, [key]: obj[key]}
}, {})
}
console.log(removeEmpty({a: 'AAA', b: '', c: 'CCC', d: false, e: null, f: [1,2], g: []}))
So your final snippet would look like this:
const updateMaster = (payload) => ({
...master, inputs: {...master.inputs, ...removeEmpty(payload)}
});
Now i have code like this:
var object = {
a: 'a',
b: 'b',
c: {
d: 'd'
}
}
_.get(object).pick(['a', 'b']).value();
How to deep pick property 'd' like:
_.get(object).pick(['a', 'b', 'c.d']).value();
you can deep destructure without lodash :
var object = {
a: 'a',
b: 'b',
c: {
d: 'd'
}
}
const { a, b, c :{ d }} = object;
console.log(a,b,d);
const obj = {a, b, d};
console.log(obj);
In case you insist in using Lodash, consider using the _.get() function:
_.get(object, 'c.d');
So, for the properties you want to get:
const selectedProps = {
..._.pick(object, ['a', 'b']),
_.get(object, 'c.d')
}
You can create a flatPick() function. The function iterates the array of paths. and uses _.get() to get the value of the path, and _.set() to add the last part of the path as property on the result object:
function flatPick(object, paths) {
const o = {};
paths.forEach(path => _.set(
o,
_.last(path.split('.')),
_.get(object, path)
));
return o;
}
var object = {
a: 'a',
b: 'b',
c: {
d: 'd',
e: {
f: 'f'
}
}
};
var result = flatPick(object, ['a', 'b', 'c.d', 'c.e.f']);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
This can work for lodash:
function pickNested(object: Json, fields: string[]) {
const shallowFields = fields.filter((field) => !field.includes('.'));
const deepFields = fields.filter((field) => field.includes('.'));
const initialValue = _.pick(object, shallowFields) as Json;
return deepFields.reduce((output, field) => {
const key = _.snakeCase(field);
output[key] = _.get(object, field);
return output;
}, initialValue);
}
and:
const json = {
id: '10',
user: {
email: 'david.i#example.com',
},
};
const newData = pickNested(json, ['id', 'user.email']);
console.log('newData ->', newData);
/*
{
id: '10',
user_email: 'david.i#example.com',
};
*/