Object.assign - merging arrays values - javascript

I have a function that returns an object like (key is string and value is array of strings):
{"myType1": ["123"]}
I want to merge all the results its returning for example - if I have:
{"myType1": ["123"]}
{"myType2": ["456"]}
{"myType1": ["789"]}
I'd like to get
{"myType1": ["123", "789], "myType2": ["456"]}
I've seen Object.assign however that doesn't merge the values it just replaces with the most recent.
Has anyone got an examples of how I can achieve this?
Any help appreciated.
Thanks.

You can the keys of an object by using Object.keys. Use forEach to loop thru the keys and modify the result object.
var result = {};
function mergeObj(o) {
Object.keys(o).forEach(k=>{
result[k] = ( result[k] || [] ).concat(o[k]);
})
}
mergeObj({"myType1": ["123"]});
mergeObj({"myType2": ["456"]});
mergeObj({"myType1": ["789"]});
console.log(result);

Make a function that adds each property to a result object, and call it with each object you get.
let res = {};
const addObj = obj => {
Object.entries(obj).forEach(([k, v]) => (res[k] = res[k] || []).push(...v));
};
addObj({"myType1": ["123"]});
addObj({"myType2": ["456"]});
addObj({"myType1": ["789"]});
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }

Here is a one liner with the desired process:
Array.from(new Set([{"myType1": ["123"]}, {"myType2": ["456"]}, {"myType1": ["789"]}].map(item => Object.keys(item)[0]).sort())).map(e => { const entry = {}; entry[e] = items.filter(item => Object.keys(item)[0] === e).map(item => item[e][0]); return entry })
Result:
[ { myType1: [ '123', '789' ] }, { myType2: [ '456' ] } ]
Regards.

Related

Pushing keys and value from an inside Obj in the Parent object

Despite the fact that the title seems difficult, let me give you a simple example.
I have an object.
{
name:"Ethan"
pets:{cat:"joline",dog:"Momo",bird"Mimi"}
}
My goal is to push the values of the array to the object.
{
name:"Ethan",
cat:"joline",
dog:"Momo",
bird"Mimi"
}
The question is simple and I believe you can approach it in a clever way, thanks.
Simple way to do this is to combine pets object and other properties using spread operator and then delete the pets from result.
const data = {
name:"Ethan",
pets:{cat:"joline",dog:"Momo",bird:"Mimi"}
}
const res = {...data, ...data.pets};
delete res.pets;
console.log(res);
If you want to do it in a functional way you can use the following approach.
Wrap the original element in a array.
Apply map on it.
Destructure pets from the object and store the rest of the properties in other variable.
Return a new object where you spread the rest object and pets.
const data = {
name:"Ethan",
pets:{cat:"joline",dog:"Momo",bird:"Mimi"}
}
const res = [data].map(({pets, ...rest}) => ({...rest, ...pets}))[0]
console.log(res)
The simplest and cleanest way to obtain desired result with destructuring.
const obj = {
name: "Ethan",
pets: { cat: "joline", dog: "Momo", bird: "Mimi" },
};
const { name, pets } = obj;
const result = { name, ...pets };
console.log(result);
Iterating through the elements and values in the object. And spreading the value into the return object
const data = {
name: "Ethan",
pets: {
cat: "joline",
dog: "Momo",
bird: "Mimi"
}
};
function flatten(data) {
let result = {};
for (const key in data) {
const value = data[key];
if (typeof value != 'object') result[key] = value;
else result = { ...result, ... flatten(value)}
}
return result;
}
console.log(flatten(data));
As others have said, this is straightforward with object destructuring. I think it's cleanest when you use parameter destructuring. So a simple function like this should do it:
const promotePets = ({pets, ...rest}) =>
({...rest, ...pets})
const obj = {name: "Ethan", pets: { cat: "joline", dog: "Momo", bird: "Mimi" }};
console .log (promotePets (obj))

How does one incrementally build a nested object structure from an array of property names?

My task is straight forward. I have an array of strings:
let a=["a","b","c"];
And i want to convert that array to (can alter the original array, doesn't matter) what i would like to call as "recursive object" just so:
//in json format just to demonstrate
"object": {
"a": {
"b":{
"c":{
}
}
}
}
I've tried the following logic but couldn't get it to work due to reference problem and i couldn't build recursion.
let tempObj;
let obj2;
array.slice().reverse().forEach(function(item,index){
obj2=tempObj;
tempObj[item]="";
});
Just to make sure we are on the same page, another example:
let arr=["alpha","beta","gamma"];
let magicObj=someMagicFunction(arr);
//magicObj["alpha"]["beta"]["gamma"] contains the value ""
Thanks
Start aggregating your object from the array's right most side via reduceRight and provide e.g. an empty object / {} or an empty string / "" as this method's initial value(s) ...
console.log(
'object :',
["a","b","c"]
.reduceRight((obj, key) =>
({ [key]: obj }), {}
)
);
console.log(
'object :',
["alpha","beta","gamma"]
.reduceRight((obj, key) =>
({ [key]: obj }), ""
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
... and since code code-reuse always should be a goal the above examples change to ...
function createObjectWithParentKeyAndChildValue(value, key) {
return { [key]: value };
}
console.log(
'object :',
['a', 'b', 'c']
.reduceRight(createObjectWithParentKeyAndChildValue, {})
);
console.log(
'object :',
['alpha', 'beta', 'gamma']
.reduceRight(createObjectWithParentKeyAndChildValue, '')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Here is a simple solution:
const arr = ["a","b","c"];
const result = arr.reverse().reduce((obj, key) => ({[key]: obj}), {})
console.log(result)
Here a little explaination:
o is the result of the last iteration and v is the current element in the array. {[v]: o} creates a new object and sets the property v to o and returns that.
The reduce / reduceRight answers are great. But this can also be done with a fairly trivial recursive version:
const buildDeep = ([p, ...ps], val) =>
p == undefined ? val : {[p]: buildDeep (ps, val)}
console .log (buildDeep (['a', 'b', 'c'], {}))
console .log (buildDeep (['alpha', 'beta', 'gamma'], ''))
To my mind, this is even simpler than reduce. It feels related to the various path-setting functions you see around, but is less complex since it doesn't have to work with an existing object.
there is my pure recursive answer:
let a=["a","b","c"];
const b = (arr = [], obj = null) => {
if (arr.length > 0) {
const { length, [length - 1]: last, ...r } = arr;
const rest = Object.values(r);
const nextObj = obj ? { [last]: obj } : { [last]: {} };
return b(rest, nextObj);
}
return obj;
};
console.log(b(a));
let magicObj = arr.reverse().reduce((obj, prop) => ({ [prop]: obj }), {})

How to reduce an array with duplicate value?

I have an array like this
let oldArray=[
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
]
if the type is the same, i want to concat the value.
The result I want is:
let newArray=[
{type:16,img:['1','2','3']},
{type:17,img:['4']}
]
I tried to used reduce function:
oldArray.reduce((acc,cur,idx,src)=>{
if(cur.type===a[idx+1].type){
cur.img.concat(a[idx+1].img);
acc.push(cur)
} else {
acc.push(a[idx+1])
}
return acc
},[])
It seems that there is an error
Can anyone help? Thanks.
Alternative to Bibberty's solution:flatMap is much clearer than reduce
let newArray = [...new Set(oldArray.map(e => e.type))]
.map(e => {
return {
type: e,
img: (oldArray.filter(i => i.type === e).map(x => x.img)).reduce((acc,cur,idx,src)=>{
let length=src.length
let tep=cur.concat(src[idx+1]);
src[idx+1]=tep
return src[idx=length-1]
},[])
}
});
console.log(newArray);
You can use reduce:
let oldArray = [{type: 16,img: ['1']},{type: 16,img: ['2']},{type: 16,img: ['3']},{type: 17,img: ['4']}];
let newArray = oldArray.reduce((acc, curr) => {
acc.some(({
type
}) => type == curr.type) ? acc.find(({
type
}) => type == curr.type).img.push(curr.img[0]) : acc.push(curr);
return acc;
}, []);
console.log(newArray);
We use a Set and then a map.
The Set is populate with the unique types by using a map to extract.
We wrap in [] to give us an array the we then re map to build our object back.
The map then rebuilds our objects and note the use of filter and map to get the img values from the original host array.
let oldArray=[
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
]
let newArray = [...new Set(oldArray.map(e => e.type))]
.map(e => {
return {
type: e,
img: oldArray.filter(i => i.type === e).flatMap(x => x.img)
}
});
console.log(newArray);
This solution is not a reduce but return result you are looking for is the same
let oldArray = [
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
];
const transitoryMap = new Map();
for (const item of oldArray) {
if (!transitoryMap.has(item.type)) {
transitoryMap.set(item.type, [item.img[0]])
} else {
const value = transitoryMap.get(item.type)
value.push(item.img[0])
transitoryMap.set(item.type, value)
}
}
const newArray = [];
for (const item of transitoryMap.keys()) {
newArray.push({type:item,img:transitoryMap.get(item)})
}
console.log(newArray)
Here is an example using reduce. I have added a tracker to keep track of type in the newArray.
let oldArray = [
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
];
oldArray.reduce((a,c)=>{
let index = a.tracker.indexOf(c.type);
if(index === -1) {
a.tracker.push(c.type);
a.newArray.push({...c, img:[...c.img]});
} else {
a.newArray[index].img.push(...c.img);
}
return a;
},{tracker:[],newArray:[]}).newArray;
You might want to consider breaking up the processing into separate simple steps, for example:
Create a flattened object with the appropriate data.
build a new array with the wanted structure.
This will not only keep your code simple, but will allow you to focus on what your code is actually doing instead of how it is doing the task.
var oldArray=[
{type:16,img:['1']},
{type:16,img:['2']},
{type:16,img:['3']},
{type:17,img:['4']}
]
flattenMyObject = (arr) =>
arr.reduce((accum, current) => {
!!accum[current.type] ? accum[current.type].push(...current.img) : accum[current.type] = current.img;
return accum;
}, {});
buildNewArray = (type) => {
return {type: type, img: flattenedObject[type] }
}
Object
.keys(flattenMyObject(oldArray))
.map(buildNewArray);

Reduce an array to a specific structure using javascript

I have an array of the objects
[
{"id":"brand","label":"Brand","value":"value1"},
{"id":"waterproof","label":"Waterproof","value":"value1"},
{"id":"diameter","label":"Diameter","value":""},
{"id":"brand","label":"Brand","value":"value2"},
{"id":"waterproof","label":"Waterproof","value":"value2"},
{"id":"diameter","label":"Diameter","value":""}
]
I need to restructure it to a following structure,
[
["Brand", "value1", "value2"],
["Waterproof", "value1","value2"],
["Diameter","",""]
]
Any ideas on how I could do this using a reduce method.
Best
Try following using Array.reduce and Object.values
let arr = [{"id":"brand","label":"Brand","value":"value1"},{"id":"waterproof","label":"Waterproof","value":"value1"},{"id":"diameter","label":"Diameter","value":""},{"id":"brand","label":"Brand","value":"value2"},{"id":"waterproof","label":"Waterproof","value":"value2"},{"id":"diameter","label":"Diameter","value":""}];
let result = Object.values(arr.reduce((a,c) => {
if(a[c.id]) a[c.id].push(c.value);
else a[c.id] = [c.label, c.value];
return a;
}, {}));
console.log(result);
Yust take a Map and collect all values.
var json = '[{"id":"brand","label":"Brand","value":"value1"},{"id":"waterproof","label":"Waterproof","value":"value1"},{"id":"diameter","label":"Diameter","value":""},{"id":"brand","label":"Brand","value":"value2"},{"id":"waterproof","label":"Waterproof","value":"value2"},{"id":"diameter","label":"Diameter","value":""}]',
result = Array.from(JSON
.parse(json)
.reduce((m, { id, label, value }) => m.set(id, (m.get(id) || [label]).concat(value)), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Not the best of code but i think this might be useful for you:
let data = [
{"id":"brand","label":"Brand","value":"value1"},
{"id":"waterproof","label":"Waterproof","value":"value1"},
{"id":"diameter","label":"Diameter","value":""},
{"id":"brand","label":"Brand","value":"value2"},
{"id":"waterproof","label":"Waterproof","value":"value2"},
{"id":"diameter","label":"Diameter","value":""}
]
let reducedData = {}
data.forEach((row)=>{
reducedData[row.id] ? reducedData[row.id].push(row.value) : reducedData[row.id] = [row.label, row.value]
})
let newData = Object.keys(reducedData).map((id)=>{return [...reducedData[id]]})
You can also use a simple combo of Array.prototype.reduce and Object.keys:
const data = [{"id":"brand","label":"Brand","value":"value1"},{"id":"waterproof","label":"Waterproof","value":"value1"},{"id":"diameter","label":"Diameter","value":""},{"id":"brand","label":"Brand","value":"value2"},{"id":"waterproof","label":"Waterproof","value":"value2"},{"id":"diameter","label":"Diameter","value":""}];
const grouped = data.reduce((o, { label, value }) =>
({...o, [label]: [...(o[label] || []), value]}), {});
const result = Object.keys(grouped).map(label => [label, ...grouped[label]]);
console.log(result);
Here I use Set to create a unique list of id's then I map to create a custom array based on those id's. This is done by using find to get the label, and filter to get all the items that are related to the id. I map again on the filter to just return the value of the object.
let items = [
{"id":"brand","label":"Brand","value":"value1"},
{"id":"waterproof","label":"Waterproof","value":"value1"},
{"id":"diameter","label":"Diameter","value":""},
{"id":"brand","label":"Brand","value":"value2"},
{"id":"waterproof","label":"Waterproof","value":"value2"},
{"id":"diameter","label":"Diameter","value":""}
]
let result = [...new Set(items.map(i => i.id))]
.map(id => {
return [
items.find(i => i.id == id).label,
...items.filter(i => i.id == id).map(i => i.value)
]
})
console.log(result)
In case the JSON Array is a very long one from some API
var data = [
{"id":"brand","label":"Brand","value":"value1"},
{"id":"waterproof","label":"Waterproof","value":"value1"},
...... //some JSON array form some API
];
var json = JSON.stringify(data);
result = Array.from(JSON
.parse(json)
.reduce((m, { id, label, value }) => m.set(id, (m.get(id) || [label]).concat(value)), new Map)
.values()
);
console.log(result);

How to convert an array to an object?

I have some data that comes like an array, i will show you it looks
Vm.table=[{
Name:"amina";
},
{
Prenom:"adfe";
},
{
Region:"rabat";
}];
To an object like
Vm.obj={
Name:"amina",
Prenom:"adfe",
Region:"rabat"
};
I need to set a code that may convert the table to this object, i put a lot of functions but is not working to me if someone can help.
You can use Object.assign() and spread operator
const table=[{Name:"amina"},{Prenom:"adfe"},{Region:"rabat"}];
const result = Object.assign({}, ...table);
console.log(result);
You can use reduce
Vm.obj = Vm.table.reduce((obj, col) => {
Object.keys(col).forEach(k => obj[k] = col[k])
return obj;
}, {});
Of course, if you have repeating keys, this will take the last key/val pair available.
Use Array.prototype.reduce and I am assuning objects have only single key, value pair.
let array =[{
Name:"amina"
},
{
Prenom:"adfe"
},
{
Region:"rabat"
}];
let obj = array.reduce((prev, curr) => {
const key = Object.keys(curr)[0];
prev[key] = curr[key];
return prev;
}, {});
console.log(obj);

Categories

Resources