Flatten nested objects using Lodash - javascript

I'm looping over object with a property set to array, which i then use in the following way:
let merged= [];
for (let sup of superObject) {
let sname = sup.superObjectName;
for (let sub of sup.subObject) {
merged.push({superObject: sname, subObject: sub.subObjectName})
}
}
Now the code above works and get job done but i feel it can be improved using Lodash and i cant get it to work. i tried using flatMap in few different ways but none seem to work, and the one in the right direction in terms of functionality wont seem like an improvement at all.
Any ideas?
UPDATE:
superObject example:
{
superObjectName: "someName",
subObject: [
{subObjectName: "someSubName"},
{subObjectName: "someSubName2"}
]
}

This does the same as your code:
const merged = _.flatMap(superObject, ({superObjectName, subObject}) =>
_.map(subObject, ({subObjectName}) => ({
superObject: superObjectName,
subObject: subObjectName
}))
);
Each value in superObject transformed to Array with map, and then flattened inside flatMap.

You can use flatMap, get props and get the desire result like this using lodash.
var data= [{
superObjectName: "someName",
subObject: [
{subObjectName: "someSubName"},
{subObjectName: "someSubName2"}
]
}];
const result = _.flatMap(data, ({ superObjectName, subObject}) =>
_.map(subObject, ({subObjectName})=> ({superObject: superObjectName, subObject: subObjectName}))
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

Related

Can destructuring an array be used to map properties of each elements?

Suppose there is an array like this:
const a = [ {p:1}, {p:2}, {p:3} ];
Is it possible to destructure this array in order to obtain p = [1, 2, 3] ?
Because this does not work :
const [ ...{ p } ] = a; // no error, same as const p = a.p;
// p = undefined;
Edit
In response to all the answers saying that I need to use Array.prototype.map, I am aware of this. I was simply wondering if there was a way to map during the destructuring process, and the answer is : no, I need to destructure the array itself, then use map as a separate step.
For example:
const data = {
id: 123,
name: 'John',
attributes: [{ id:300, label:'attrA' }, { id:301, label:'attrB' }]
};
function format(data) {
const { id, name, attributes } = data;
const attr = attributes.map(({ label }) => label);
return { id, name, attr };
}
console.log( format(data) };
// { id:123, name:'John', attr:['attrA', 'attrB'] }
I was simply wondering if there was a way, directly during destructuring, without using map (and, respectfully, without the bloated lodash library), to retrive all label properties into an array of strings.
Honestly I think that what you are looking for doesn't exist, normally you would map the array to create a new array using values from properties. In this specific case it would be like this
const p = a.map(element => element.p)
Of course, there are some packages that have many utilities to help, like Lodash's map function with the 'property' iteratee
you can destructure the first item like this :
const [{ p }] = a;
but for getting all values you need to use .map
and the simplest way might be this :
const val = a.map(({p}) => p)
Here's a generalized solution that groups all properties into arrays, letting you destructure any property:
const group = (array) => array.reduce((acc,obj) => {
for(let [key,val] of Object.entries(obj)){
acc[key] ||= [];
acc[key].push(val)
}
return acc
}, {})
const ar = [ {p:1}, {p:2}, {p:3} ];
const {p} = group(ar)
console.log(p)
const ar2 = [{a:2,b:1},{a:5,b:4}, {c:1}]
const {a,b,c} = group(ar2)
console.log(a,b,c)

Mapping through an array to produce an object

I have an array :
[
"2022-05-20",
"2022- 06-22",
"2022-06-20"
]
and I want to produce an object like this:
{
'2022-05-20': {disabled:true},
'2022-06-22': {disabled: true},
'2022-06-20': {disabled: true},
}
I tried using a for loop but it kept producing errors. Is this possible with javascript?
You can use Array#reduce as in the following demo. You can also use Array#map but you would have to use Object.fromEntries as well.
const input = [ "2022-05-20", "2022- 06-22", "2022-06-20" ],
output = input.reduce(
(prev,cur) =>
({...prev,[cur]:{disabled:true}}), {}
);
console.log( output );
USING Array#map ...
Here is how you can use Array#map:
const input = [ "2022-05-20", "2022- 06-22", "2022-06-20" ],
output = Object.fromEntries(
input.map(date => [date, {disabled:true}])
);
console.log( output );
Can do it:
let dates = [
"2022-05-20",
"2022- 06-22",
"2022-06-20"
];
let newObj = Object.assign(...dates.map(key => ({[key]: {disabled: true}})));
console.log(newObj)
This might get the job done.
const yourArray = ["2022-05-20", "2022-06-22", "2022-06-20"];
const obj = {};
for(const x of yourArray) obj[String(x)] = { disabled: true };
console.log(obj); // :)
Create the variable obj that is going to save the produced object you want. Iterating throw your array and using a string parsed version of the value in the current iteration (parsing just in case, if you already know the array is made of strings, this is kinda unnecessary) to save it as a key on the new object, also assigning to that key, the value { disabled: true }.
Here is a one liner solution:
let res = data.reduce((acc, curr) =>(acc[curr] = {disabled: true}, acc), {});

Lodash move objects under a key part of same object

I have an JSON object like
datas = [
{"id":1,"name":"Test","age":24},
{"id":2,"name":"Test1","age": 30}
]
I want to modify the JSON object like below
datas = [
{"1":{"name":"Test","age":24}},
{"2":{"name":"Test1","age": 30}}
]
I want to do the same using lodash . I can understand map over the data and create a new object should fix this
updated_data=[]
_.map datas, (data) ->
Obj = {}
Obj[data.id] = data
updated_data.push(Obj)
But I am looking for lodash way of achieving the same .
Use Array.map() (or _.map()) with destructuring and object rest (...):
const datas = [{"id":1,"name":"Test","age":24}, {"id":2,"name":"Test1","age": 30}]
const result = datas.map(({ id, ...o }) => ({ [id]: o }))
console.log(result)
With lodash you can do the same, but instead of destructuring use _.omit() to remove the id from the original object, and use _.zipObject() combine it with the id:
const datas = [{"id":1,"name":"Test","age":24}, {"id":2,"name":"Test1","age": 30}]
const result = _.map(datas, o => _.zipObject([o.id], [ _.omit(o, 'id')]))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
I think you don't need to use an extra library for this. This way you can achieve the desired result:
datas.map((item) => {
const { id, ...rest } = item;
return {
id: rest,
};
});

Map an array to an object, using array values as keys

I have
const menu = ['home', 'news', 'about'];
I want to map it to this:
let menuExt =
{
home: Common.locs['home'],
news: Common.locs['news'],
about: Common.locs['about']
};
How do I do that? I tried
let menuExt = menu.map(item => {
return {
item: Common.locs[item]
}
});
but I got an array with "item" as property, but I want one object with properties home, news, about... (there are many more but I shortened it here)
menu.map(item => {menuExt[item]=Common.locs[item]});
I managed this way, but I don't know if there is a cleaner and faster solution maybe:
let menuExt = {}
menu.forEach((item) => {
menuExt[item] = Common.locs[item]
});
The idiomatic way would be to use Array.reduce, because you're taking an array of objects and returning a single object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
const menu = ['home', 'news', 'about'];
const menuExt = menu.reduce((acc, key) => {
acc[key] = Common.locs[key];
return acc;
}, {});

React How to merge an array and an array of objects

I have this two states:
stateOne: [
'marca01',
'marca02'
]
stateTwo: [
{
PRODUCTO:'hat',
PRICE:1499,
CATEGORY:'Men'
},
{
PRODUCTO:'Shirt',
PRICE:1233,
CATEGORY:'Woman'
}
]
And I'm using lodash to merge both in a third state, but as you see the first state is an array and the second one is an array of objects so I can't merge these two like I want to...
Something like this:
stateThree: [
{
PRODUCTO:'hat',
PRICE:1499,
CATEGORY:'Men',
MARK:'marca01'
},
{
PRODUCTO:'Shirt',
PRICE:1233,
CATEGORY:'Woman',
MARK:'marca02'
}
]
How can I get the desired result (is not necessary to use lodash)
Without lodash :
const state3 = state2.map((product, index) => ({
...product,
MARK: state1[index]
}));
Here .map returns a new array whose new values are returned by the anonymous function.
The spread operator ...product flattens the previous object properties in the new object. This syntaxic sugar can be replaced by Object.assign.
Then we add a new MARK property based on the other state with the same index.
I used the map method and the spread operator in order to prevent state mutation which can be harmful in React.
You could iterate over the second array, and add the properties.
let s1 = [
'marca01',
'marca02'
]
let s2 = [
{
PRODUCTO:'hat',
PRICE:1499,
CATEGORY:'Men'
},
{
PRODUCTO:'Shirt',
PRICE:1233,
CATEGORY:'Woman'
}]
s2.forEach((x,i) => x.MARK = s1[i])
console.log(s2)
You can do like this:
stateThree = stateTwo.map( (element, i) => ({...element, MARK: stateOne[i] } ))

Categories