reduce method JavaScript, convert 2 objects in a single one - javascript

I have this array of objects:
const array = [{name: 'chips', size: 'medium'}, {name: 'burguer', size: 'large'}].
And I want to convert it to this:
{description: 'chips medium, burguer large'}
How can I do it? I have been trying with reduce without success.

You can achieve your desired result using a nested map and joins to first join each of the object values in the array and then the elements of the array into the final output:
const array = [{name: 'chips', size: 'medium'}, {name: 'burguer', size: 'large'}]
const result = { description :
array.map(obj => Object.values(obj).join(' ')).join(', ')
}
console.log(result)
Note it's possible the values in the object may not come out in the expected order (especially if you have modified the object) so it may be safer to refer to the properties directly:
const array = [{name: 'chips', size: 'medium'}, {name: 'burguer', size: 'large'}]
const result = { description :
array.map(({ name, size }) => `${name} ${size}`).join(', ')
}
console.log(result)

const array = [{name: 'chips', size: 'medium'}, {name: 'burguer', size: 'large'}];
const result = array.reduce((sum, cur) => {
if (!sum.description) {
sum.description = `${cur.name} ${cur.size}`;
return sum;
}
sum.description += `, ${cur.name} ${cur.size}`;
return sum;
}, {});
console.log(result);

You can use the Array#reduce method as follows but, as shown by #Nick using the Array#map method is more straightforward.
const array = [{name: 'chips', size: 'medium'}, {name: 'burguer', size: 'large'}],
output = array.reduce(
({description:d},{name,size}) =>
({description: (d ? `${d}, ` : "") + `${name} ${size}`}),
{});
console.log( output );

This can be implemented only using reduce method (not using maps) as below
const array = [{ name: 'chips', size: 'medium' }, { name: 'burguer', size: 'large' }]
const result = {
description: array.reduce((previousValue, currentValue) =>
Object.values(previousValue).concat(Object.values(currentValue).join(' ')), [],).toString()
}
console.log(result);
I think it is a good idea to go through "Sum of values in an object array" and "Flatten an array of arrays" in the mozilla documentation.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

Related

I would like to avoid using `.flat()` and use `.reduce` instead in JavaScript

I have
an array of strings const rooms = ['roomA', 'roomB', 'roomC'].
an object that has
const roomOccupants = {
'roomA': [{name: 'player1'}, {name: 'player555'}],
'roomB': [{name: 'player2'}, {name: 'player3'}]
}
I have added the players from roomA & roomB to a new room say roomABC using the map function below however roomABC needs to be flattened using .flat() array method bc the returned value structure is [{}, {}], [{}, {}].
I was wondering if there is a way that I could avoid using .flat() maybe using .reduce() could achieve that but I was not able to figure it out.
const roomABC = rooms.map((roomName) => {
return roomOccupants[roomName];
});
I need the output to be as follows. No need for unique items/order of the items in the array. Thanks in advance.
const roomABC = [{name: 'player1'}, {name: 'player2'}, {name: 'player3'}, {name: 'player555'}]
const rooms = ['roomA', 'roomB', 'roomC'];
const roomOccupants = {
'roomA': [{name: 'player1'}, {name: 'player555'}],
'roomB': [{name: 'player2'}, {name: 'player3'}]
};
const roomABC = rooms.reduce((acc,curr) => {
if(roomOccupants[curr]){
acc = acc.concat(roomOccupants[curr]);
}
return acc;
},[]);
console.log(roomABC);
/* Prints :
[
{
"name": "player1"
},
{
"name": "player555"
},
{
"name": "player2"
},
{
"name": "player3"
}
]
*/
Here acc is the accumulated result and curr is the current value.
The reducer function gets called for every element of the rooms array. So in the above code snippet, curr will take values "room1", "room2", and "room3".
We start with an empty list, [] as the initial value of acc.
The function checks if roomOccupants[curr] exists and if it does, concatenates it's value with the previous value of acc.
Hope this helps!
The following would be the code for non-repeating players:
const rooms = ['roomA', 'roomB', 'roomC'];
const roomOccupants = {
'roomA': [{name: 'player1'}, {name: 'player555'}],
'roomB': [{name: 'player1'}, {name: 'player3'}],
'roomD': [{name: 'harry'}]
};
const roomABC = Object.values(rooms.reduce((a,r,os) =>{
if (os=roomOccupants[r])
os.forEach(o=>a[o.name]=o);
return a;
},{}))
console.log(roomABC);

Flatten array of objects

I have an array of objects coming from a formData serializeArray function. For example:
[
0 : {name: 'animal_monkey', value: 'banana'}
1 : {name: 'animal_horse', value: 'radishes'}
2 : {name: 'fruit_banana', value: 'yellow'}
3 : {name: 'fruit_apple', value: 'red'}
]
I am looking for a way to get these different elements into a single object, split by category with their appropriate value assigned, like so:
{
animal: {
monkey : banana,
horse : radishes
},
fruit: {
banana : yellow,
apple : red
}
}
I have tried doing this with reduce and Object assign, like so
obj = keys.map((k, i) => k.reduceRight((value, key) => ({[key]: value}), vals[i]) )
result = Object.assign({}, ...obj)
where keys is an array of ['animal_monkey', 'animal_horse', 'fruit_banana', 'fruit_apple'] and vals is a list with values: ['banana', 'radishes', 'yellow', 'red']. However, perhaps as expected, the values are overwritten and I end up with:
{
animal: {
horse : radishes
},
fruit: {
apple : red
}
}
The first value(s) don't survive the assignment. Does anyone have a good idea how to make this work?
Thanks!
You can split each name on _ and then create an object with the category and animal name using array#reduce.
const data = [ {name: 'animal_monkey', value: 'banana'}, {name: 'animal_horse', value: 'radishes'}, {name: 'fruit_banana', value: 'yellow'}, {name: 'fruit_apple', value: 'red'} ],
result = data.reduce((r,o) => {
const [category, name] = o.name.split('_');
r[category] ??= {};
r[category][name] = o.value;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can set a variable that will hold the final combined object, then add to it for each element in the array using array.forEach
let single = {};
arr.forEach(obj => {
let [catagory, name] = obj.name.split('_'); // catagory = before the _, name = after the _
single[catagory] ??= {}; // make sure the catagory exists as an object in single
single[catagory][name] = obj.value;
}

break up key value pairs into separate objects with the same keys [duplicate]

This question already has answers here:
Convert object to array of key–value objects like `{ name: "Apple", value: "0.6" }`
(3 answers)
Closed 1 year ago.
I'm sorry if this is redundant with other posts but I currently have the following array:
let test = {1:100, 2:200, 3:300}
But I'd like to convert this to:
test = [
{id: 1, value: 100},
{id: 2, value: 200},
{id: 3, value: 300}
]
Any help appreciated - even just pointing me to posts that solve this question :)
You can use Object.entries to get an array of key, value pairs and then map that to an array of objects:
let test = {1:100, 2:200, 3:300};
let out = Object.entries(test).map(([k, v]) => ({ id : k, value: v }));
console.log(out);
Here's a version using keys and map:
var obj = {1:100,2:200,3:300}
var result = Object.keys(obj).map((key) => ({ id: key, value: obj[key]}));
console.log(result)
Using Object.entries() and some destructuring
let test = {1:100, 2:200, 3:300}
let res = Object.entries(test).map(([id, value]) => ({id, value}))
console.log(res)

How to decompose an object and make it the following structure with help of reduce function

how to create with help of reduce method next structure
let events = {
'2019-12-29': ['name1', 'name3', 'name5', 'name7'],
'2019-12-30': ['name4', 'name8', 'name9'],
'2019-12-31': ['name2', 'name6'],
}
====>how to make this structure
let events = [
{
date: '2019-12-29'
event: 'name1'
},
{
date: '2019-12-31'
event: 'name2'
},
{
date: '2019-12-29'
event: 'name3'
},
...
]
Here is how you can use reduce
Object.keys(events).reduce((acum, cur) => {
events[cur].forEach((n) => {
acum.push({ date: cur, event: n });
});
return acum;
}, []);
You can then sort the above array by the name field
I wanted to mention that reduce normally used to convert an array to an object which is not similar to your use case!
You need to convert the object to an array that's why using Object.keys
You can use Object.entries() and then reduce() function:
let events = { "2019-12-29": ['name1', 'name3', 'name5', 'name7'], "2019-12-30": ['name4', 'name8', 'name9'], "2019-12-31": ['name2', 'name6']};
let output = Object.entries(events).reduce((arr, ent) =>
[...arr, ...ent[1].map(n => ({date: ent[0], event: n}))],
[]);
console.log(output);
You can use Object.entries to get all the entries of the object and reduce by iterating over all the dates for an event, and pushing them to the accumulator array.
let events = {
'2019-12-29': ['name1', 'name3', 'name5', 'name7'],
'2019-12-30': ['name4', 'name8', 'name9'],
'2019-12-31': ['name2', 'name6'],
}
const res = Object.entries(events)
.reduce((acc,[date,names])=>(names.forEach(event=>acc.push({date,event})),acc),[]);
console.log(res);

Mapping the array element with other array

I have two arrays
array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
array2 = [{tags: "1",title: "USA",type: "text"},
{tags: "1,2,3",title: "Japan",type: "image"},
{tags: "2,3",title: "Japan",type: "image"}];
I have to map the id of the array1 to tags of the array2 and display the corresponding title from the array1.
The new array2 should look like,
array2=[{tags:"Writing",title:"USA", type:"text"},
{tags: "Writing,Singing,Dance",title: "Japan",type: "image"},
{tags: "Singing,Dance",title: "Japan",type: "image"}];
I did this to get the array1 mapping and got stuck after that.
var newtags= (array1).map(obj=>{
var rObj={};
rObj[obj.id]=obj.title;
return rObj;
});
You can create a mapping object with each id as key and title as value using reduce. Then map over array2 and split each tags to get the new tags
const array1=[{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}],
array2=[{tags:"1",title:"USA",type:"text"},{tags:"1,2,3",title:"Japan",type:"image"},{tags:"2,3",title:"Japan",type:"image"}]
const map = array1.reduce((r, { id, title }) => ({ ...r, [id]: title }), {});
const output = array2.map(({ tags, ...rest }) => {
const newTags = tags.split(',').map(id => map[id]).join(',')
return { tags: newTags, ...rest }
})
console.log(output)
You could also get the mapping object using Object.fromEntries()
const map = Object.fromEntries(array1.map(({ id, title }) => [id, title]));
Then use the regex /\d+(?=,|$)/ to match the numbers and replace them with their respective titles
const array1=[{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}],
array2=[{tags:"1",title:"USA",type:"text"},{tags:"1,2,3",title:"Japan",type:"image"},{tags:"2,3",title:"Japan",type:"image"}]
const map = Object.fromEntries(array1.map(({ id, title }) => [id, title]));
const output = array2.map(({ tags, ...rest }) => {
const newTags = tags.replace(/\d+(?=,|$)/g, n => map[n])
return { tags: newTags, ...rest }
})
console.log(output)
Here's a solution
I'm using .map, .reduce and .replace to join array1 and array2 together.
const array1 = [
{
id: "1",
title: "Writing"
},
{
id: "2",
title: "Singing"
},
{
id: "3",
title: "Dance"
}
]
const array2 = [
{
tags: "1",
title: "USA",
type: "text"
},
{
tags: "1,2,3",
title: "Japan",
type: "image"
},
{
tags: "2,3",
title: "Japan",
type: "image"
}
]
const array3 =
array2.map(item => ({
...item,
tags: array1.reduce((tags, {id, title}) => tags.replace(id, title), item.tags),
}))
console.log(array3)
You can use filter, map and join method, split tags and filter tags in array1 first.
var newtags= (array2).map(obj=>{
let tags = obj.tags.split(",");
let titles = array1.filter(c=>tags.includes(c.id)).map(c=>c.title);
obj.tags = titles.join();
return obj;
});
array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
array2 = [{tags: "1",title: "USA",type: "text"},
{tags: "1,2,3",title: "Japan",type: "image"},
{tags: "2,3",title: "Japan",type: "image"}];
var newtags= (array2).map(obj=>{
let tags = obj.tags.split(",");
let titles = array1.filter(c=>tags.includes(c.id)).map(c=>c.title);
obj.tags = titles.join();
return obj;
});
console.log(newtags);
You can try following
Use Array.reduce to convert array1 into an object with id as key and title as value (Step 1)
Iterate over array2 using Array.forEach to update its tags property
To update tags property first split it by , to convert into an array
Map each value in array to its corresponding value in Object created in step 1
Join back the array with , and assign back to tags
let array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
let array2 = [{tags: "1",title: "USA",type: "text"},{tags: "1,2,3",title: "Japan",type: "image"},{tags: "2,3",title: "Japan",type: "image"}];
let obj = array1.reduce((a,c) => Object.assign(a, {[c.id] : c.title}), {});
array2.forEach(o => o.tags = o.tags.split(",").map(v => obj[v]).join(","));
console.log(array2);
To achieve expected result, use below option of looping array1 and replacing array2 tags with title
Loop Array1 using forEach
Replace array2 tags with each array1 title using array id
array1 = [{id:"1",title:"Writing"},{id:"2",title:"Singing"},{id:"3",title:"Dance"}];
array2 = [{tags: "1",title: "USA",type: "text"},
{tags: "1,2,3",title: "Japan",type: "image"},
{tags: "2,3",title: "Japan",type: "image"}];
array1.forEach(v =>{
const re = new RegExp(v.id, "g");
array2 = JSON.parse(JSON.stringify(array2).replace(re, v.title))
})
console.log(array2);
I would consider breaking this down into several reusable functions. Of course it might be premature abstraction, but I've seen variants of this questions like often enough here that it makes sense to me to look toward the fundamentals.
We want to be able to look up the values in a list stored as an array with what might be arbitrary field names. So we use a function makeDictionary that takes both the field names and the array and returns an object that maps them, such as {'1': 'Writing', '2': 'Singing',...}`.
Then we can use fillField supplying a dictionary, a field name, and an object, and replace that field with the result of looking up the tags in the dictionary. This is a little more specific to the problem, mostly because the comma-separated string format for your tags is a little more cumbersome than it might be if it were an array.
With these, useTags is simple to write, and it is the first function here focused directly on your needs. It combines the above, supplying the field names id and title for the dictionary and tags for your main objects.
This is what it looks like combined:
const makeDictionary = (keyName, valName) => (arr) =>
arr .reduce
( (a, {[keyName]: k, [valName]: v}) => ({...a, [k]: v})
, {}
)
const fillField = (field, dict) => ({[field]: f, ...rest}) => ({
...rest,
[field]: f .split (/,\s*/) .map (t => dict[t]) .join (', ')
})
const useTags = (tags, dict = makeDictionary ('id', 'title') (tags) ) =>
(objs) => objs .map ( fillField ('tags', dict) )
const tags = [{id: "1", title: "Writing"}, {id: "2", title: "Singing"}, {id: "3", title: "Dance"}];
const updateTags = useTags (tags)
const items = [{tags: "1", title: "USA", type: "text"}, {tags: "1, 2, 3", title: "Japan", type: "image"}, {tags: "2, 3", title: "Japan", type: "image"}];
console .log (
updateTags (items)
)
Note that I took a little liberty with the tags: "2,3" and tags: "Singing,Dance" formats, adding a little white space. It's trivial to take this out. But even better, if possible, would be to change this to use arrays for your tags.
You could take a real Map and map the values to the new objects.
var array1 = [{ id: "1", title: "Writing" }, { id: "2", title: "Singing" }, { id: "3", title: "Dance" }],
array2 = [{ tags: "1", title: "USA", type: "text" }, { tags: "1,2,3", title: "Japan", type: "image" }, { tags: "2,3", title: "Japan", type: "image" }],
tags = array1.reduce((m, { id, title }) => m.set(id, title), new Map),
result = array2.map(o => ({ ...o, tags: o.tags.split(',').map(Map.prototype.get, tags).join() }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources