How to optimize reducer function - javascript

I have this function
const joinCages = arr => {
return arr.reduce((acc, { jaulaId, comunaCode }) => {
if (!acc.hasOwnProperty(jaulaId)) acc[jaulaId] = []
acc[jaulaId].push(comunaCode)
return acc
}, {})
}
The output is this:
{
JAU0000001: [ '130109' ],
JAU0000029: [ '100102', '100103' ],
JAU0000017: [ '100304', '100305' ]
}
What it does:
Create an object that group the "Comuna Code" in the key "jaula ID" from an array of objects
Data array
[
{
indexId: 104834,
jaulaId: "JAU0000001",
distributionCenterId: "100",
comunaCode: "130109",
orderType: "Retorno",
regionCode: "13"
},
{
indexId: 104836,
jaulaId: "JAU0000029",
distributionCenterId: "100",
comunaCode: "100102",
orderType: "Retorno",
regionCode: "13"
},
{
indexId: 104837,
jaulaId: "JAU0000029",
distributionCenterId: "100",
comunaCode: "100103",
orderType: "Retorno",
regionCode: "13"
}
]
I want to upgrade that function without the if statement and removing the return...Return implicit you know?
The problem is that I am failing coding this and I dont know where or how can I do this.
Upgraded function
const joinCages2 = arr => {
return arr.reduce((acc, { jaulaId, comunaCode }) => ({
...acc,
[jaulaId]: [jaulaId] ? [jaulaId].push(comunaCode) : [comunaCode]
}), {})
}
Thank you in advance.

Related

How to flatten nested array of objects and create new array

I have a data structure as the following
[
{
"models":[
{
"name":"xyz",
"options":[
{
"label":"blue"
},
{
"label":"brown"
},
]
},
{
"name":"abc",
"options":[
{
"label":"yellow"
}
]
},
{
"name":"def",
"options":[
{
"label":"green"
}
]
}
]
}
]
The end result should be an array with all of the labels and name like xyz: blue, xyz: brown, abc: yellow, def: green
so something like this
['xyz: blue', 'xyz: brown', 'abc: yellow','def: green']
I'm trying different approaches, one with RxJS operators and another with reduce
let flat = (acc, current) => {
}
models.reduce(flat, [])
You can use a reduce and a map like this.
const arr = [
{
"models":[
{
"name":"xyz",
"options":[
{
"label":"blue"
},
{
"label":"brown"
},
]
},
{
"name":"abc",
"options":[
{
"label":"yellow"
}
]
},
{
"name":"def",
"options":[
{
"label":"green"
}
]
}
]
}
];
const result = arr[0].models.reduce(
(acc, model) => [...acc, ...model.options.map(i => ({ [model.name]: i.label }))]
, []
);
console.log(result);
If the top level array can have multiple items rather than arr[0] you would need to add another reduce feeding it's accumulator in to the second reduce as it's starting accumulator rather than the empty starting array.
const arr = [
{
"models":[
{
"name":"xyz",
"options":[
{
"label":"blue"
},
{
"label":"brown"
},
]
},
{
"name":"abc",
"options":[
{
"label":"yellow"
}
]
},
{
"name":"def",
"options":[
{
"label":"green"
}
]
}
]
},
{
"models":[
{
"name":"ghi",
"options":[
{
"label":"gold"
},
{
"label":"pink"
},
]
}
]
}
];
const result = arr.reduce(
(acc, item) =>
item.models.reduce(
(acc2, model) => [...acc2, ...model.options.map((i) => ({ [model.name]: i.label }))]
, acc
),
[]
);
console.log(result);
Not sure where RxJs comes into this question but if you are looking to transform an object like this that comes back from a http request you would pipe it into the map operator and then use this function inside the map. If you are looking to do a reduce on a stream there is a reduce operator that emits the accumulator when the source stream completes or the scan operator that emits the accumulator each time the source emits.
Use nested calls to flatMap(), and in the innermost call you concatenate the model name with the option label.
const data = [{
"models": [{
"name": "xyz",
"options": [{
"label": "blue"
},
{
"label": "brown"
},
]
},
{
"name": "abc",
"options": [{
"label": "yellow"
}]
},
{
"name": "def",
"options": [{
"label": "green"
}]
}
]
}];
let result = data.flatMap(d => d.models.flatMap(model => model.options.map(option => `${model.name}: ${option.label}`)));
console.log(result);
Here is using multiple forEach and destructuring
const flat = (arr, res = []) => {
arr.forEach(({ models }) =>
models.forEach(({ name, options }) =>
options.forEach(({ label }) => res.push({ [name]: label }))
)
);
return res;
};
const data = [
{
models: [
{
name: "xyz",
options: [
{
label: "blue",
},
{
label: "brown",
},
],
},
{
name: "abc",
options: [
{
label: "yellow",
},
],
},
{
name: "def",
options: [
{
label: "green",
},
],
},
],
},
];
console.log(flat(data));
const response = array[0].models.reduce((initial, model) => {
if (model.options.length === 1)
initial.push(`${model.name}: ${model.options[0].label}`);
else {
model.options.forEach((option) =>
initial.push(`${model.name}: ${option.label}`),
);
}
return initial;
}, []);
console.log(response)
;
// there is no need if the inner option has just one object you can just access it by model.options[0].label, that why there is a check to see if it one

Group array of objects with a specific key value pushed first

Given the following Array of Objects:
[
{
"teamFK": 8650,
"code": "yellow_cards",
"typeId": 554,
"value": "5",
"side": "home"
},
{
"teamFK": 8650,
"code": "goals",
"typeId": 554,
"value": "1",
"side": "home"
},
{
"teamFK": 8990,
"code": "yellow_cards",
"typeId": 555,
"value": "2",
"side": "away"
},
{
"teamFK": 8990,
"code": "goals",
"typeId": 555,
"value": "0",
"side": "away"
}
]
I would like to group this data by code and get this result:
{
"stats": [
{
"name": "yellow_cards",
"stats": ["5","2"]
},
{
"name": "goals",
"stats": ["2","0"]
}
]
}
What I've done is the following which works but I want to make sure that the alway the stat with "side":"home" always pushed first into the array "stats": []:
const groupedStats = Object.entries(
query.reduce((acc, { typeId, value, code, side }) => {
if (!acc[code]) {
acc[code] = [];
}
acc[code].push(value);
return acc;
}, {}),
).map(([name, stats]) => ({ name, stats }));
My approach is sort it first by side using Array.sort() and then looping through the objects and adding it to stats
i created a const match to find if there is a match already so i dont have to add the name and value again basically if its not a match i'll add it to the stats array and if its a match then i'll just update the current index
const objs = [
{
teamFK: 8650,
code: "yellow_cards",
typeId: 554,
value: "5",
side: "home",
},
{
teamFK: 8650,
code: "goals",
typeId: 554,
value: "1",
side: "away",
},
{
teamFK: 8990,
code: "yellow_cards",
typeId: 555,
value: "2",
side: "away",
},
{
teamFK: 8990,
code: "goals",
typeId: 555,
value: "0",
side: "home",
},
];
let stats = [];
const transformedObj = objs
.sort((a, b) => {
if (a.side > b.side) {
return -1;
}
if (a.side < b.side) {
return 1;
}
return 0;
})
.forEach((obj) => {
const match = stats.find((stat) => stat.name === obj.code);
const statsIndex = stats.findIndex((stat) => stat.name === obj.code);
if (!match) {
stats = [...stats, { name: obj.code, value: [obj.value] }];
} else {
stats[statsIndex] = {
name: stats[statsIndex].name,
value: [...stats[statsIndex].value, obj.value],
};
}
});
console.log(stats);
You can sort array and use key grouping approach:
const data = [{"teamFK": 8650,"code": "yellow_cards","typeId": 554,"value": "5","side": "home"},{"teamFK": 8650,"code": "goals","typeId": 554,"value": "1","side": "home"},{"teamFK": 8990,"code": "yellow_cards","typeId": 555,"value": "2","side": "away"},{"teamFK": 8990,"code": "goals","typeId": 555,"value": "0","side": "away"}];
const groups = data
.sort(({ side: a }, { side: b }) => b.localeCompare(a))
.reduce((acc, { code, value }) => {
acc[code] ??= { name: code, stats: [] };
acc[code]['stats'].push(value);
return acc;
}, {});
const result = { stats: Object.values(groups) };
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }

Array of object into a nested object for every value in the array

Trying to turn an array of objects into a nested object. Is there a good method for this? and how do I make it depending on the array length?
Working but is not universal:
https://codesandbox.io/s/thirsty-roentgen-3mdcjv?file=/src/App.js
What I have:
sorting: [
{
"id": "HighestDegree",
"options": [
"HighSchool",
"Undergraduate",
"Bachelor",
"Master",
"Doctor"
]
},
{
"id": "gender",
"options": [
"male",
"female"
]
}
]
What I want:
value: {
"Region": "Oklahoma",
"HighestDegree": {
"HighSchool": {
"male": null,
"female":null
},
"Undergraduate":{
"male": null,
"female":null
}
//and so on...
}
}
The code beneath works but is hardcoded for only two different options. I want it to be able to nest the length of the array. So lets say another object was age it would be {"HighSchool":{male:{"<25":null,"25-35":null}}} etc..
function testSortingArray() {
let sorting = [
{
id: "HighestDegree",
options: ["HighSchool", "Undergraduate", "Bachelor", "Master", "Doctor"]
},
{
id: "gender",
options: ["male", "female"]
}
];
let GoalArray = {};
if (sorting.length > 0) {
sorting[0].options.map((firstArray) => {
let currObject = {};
sorting[1].options.map((secondOption) => {
currObject[secondOption] = null;
});
GoalArray[firstArray] = currObject;
});
}
return GoalArray;
}
console.log(testSortingArray());
You can do it with a recursive function.
The function below reduces every options array to an object, and then continues populating that object if there are rest elements left from the original sorting array.
const fn = ([{ options }, ...rest]) => options.reduce((a, v) => ({
...a,
[v]: rest.length ? fn(rest): null
}), {});
const result = fn(sorting);
Besides the reduce() method, the code above makes use of object and array destructuring and spread syntax.
Complete snippet:
const sorting = [{
"id": "HighestDegree",
"options": [
"HighSchool",
"Undergraduate",
"Bachelor",
"Master",
"Doctor"
]
}, {
"id": "gender",
"options": [
"male",
"female"
]
}, {
"id": "age",
"options": [
"<25",
"25-35"
]
}];
const fn = ([{ options }, ...rest]) => options.reduce((a, v) => ({
...a,
[v]: rest.length ? fn(rest): null
}), {});
const result = fn(sorting);
console.log(result);

javascript group a nested array of objects by child object value

Im trying to group an array of objects by a value of one of the child objects.
Im kinda getting want I want using reduce, but it seems to be combining the group by value where the parent objects are common.
let name = [
{
issue: "89",
status: ["test", "prod", "dev"]
},
{
issue: "45",
status: ["dev"]
}
];
const groups = name.reduce((groups, item) => {
const group = groups[item.status] || [];
group.push(item);
groups[item.status] = group;
return groups;
}, {});
console.log(JSON. stringify(groups));
I get the below results
{
"test,prod,dev":[
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
],
"dev":[
{
"issue":"45",
"status":[
"dev"
]
}
]
}
What id like is for it the produce the below:
{
"prod":[
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
],
"test":[
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
],
"dev":[
{
"issue":"45",
"status":[
"dev"
]
},
{
"issue":"89",
"status":[
"test",
"prod",
"dev"
]
}
]
}
Im not sure how to produce my desired results easily.
many thanks
You need to group your object based on the status. You can use array#reduce with array#forEach.
const names = [ { issue: "89", status: ["test", "prod", "dev"] }, { issue: "45", status: ["dev"] } ],
result = names.reduce((r, o) => {
o.status.forEach(name => {
r[name] ??= [];
r[name].push(JSON.parse(JSON.stringify(o)));
});
return r;
},{});
console.log(result);
const group = Object.assign({}, ...name.reduce((p, c) => [...p, ...c.status], [])
.filter((v, i , a) => a.indexOf(v) === i)
.map(item => ({ [item]: name.filter(old => old.status.includes(item)) })))

How to make a array from another array with grouping data based on id .?

I have an array object as follows,
const data = [
{
"order_id":"ORDCUTHIUJ",
"branch_code":"MVPA",
"total_amt":199500,
"product_details":[
{
"image":"CC252.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORHOGFD79L",
"branch_code":"PBVR",
"total_amt":325880,
"product_details":[
{
"image":"1617382086515.jpg",
"cate":"Mobile Accessories"
},
{
"image":"1617382322759.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC251.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORIYDJLYSJ",
"branch_code":"MVPA",
"total_amt":1549500,
"product_details":[
{
"image":"CC250.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC256.jpg",
"cate":"Mobile Accessories"
}
]
}
]
what I want to achieve is to build a new array based on this, but I want to group the data with the same branch code under one object.
Expected Output:
const newData =
[
{
MVPA: [
{
order_id: 'ORIYDJLYSJ',
(otherdetails)
},
{
order_id: 'ORDCUTHIUJ',
(otherdetails
}
]
},
PBVR: [
{
order_id: 'ORHOGFD79L',
(otherdetails)
}
]
can someone help me out on how to achieve this.? I want a general solution, bcoz this data could be longer than this when I get from DB.
You can do it with Array.reduce.
data.reduce((o, a) => (o[a.branch_code] = [ ...(o[a.branch_code] || []), a], o), {})
First create an object which collects data with branch_code.
const obj = data.reduce((map,obj)=>{
if(obj.branch_code in map){
map[obj.branch_code].push({...obj})
}
else{
map[obj.branch_code]=[{...obj}]
}
return map
},{})
This gives
{MVPA: Array(2), PBVR: Array(1)}
Then,map over the keys of the above object to create your required array.
const result = Object.keys(obj).map(key => ({[key]:
[...obj[key]]}))
console.log('result',result)
This gives
(2) [{…}, {…}]
0: {MVPA: Array(2)}
1: {PBVR: Array(1)}
const uniqueBranchCode = [...new Set(data.map(i => i.branch_code))] // Get unique branch_code
const newData = uniqueBranchCode
.map(order => data.filter(orderSpecific => orderSpecific.branch_code === order)) // Filter to group together by branch_code
.map(item => ({[item[0].branch_code]: item})) // Assign key and return elements
const data = [
{
"order_id":"ORDCUTHIUJ",
"branch_code":"MVPA",
"total_amt":199500,
"product_details":[
{
"image":"CC252.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORHOGFD79L",
"branch_code":"PBVR",
"total_amt":325880,
"product_details":[
{
"image":"1617382086515.jpg",
"cate":"Mobile Accessories"
},
{
"image":"1617382322759.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC251.jpg",
"cate":"Mobile Accessories"
}
]
},
{
"order_id":"ORIYDJLYSJ",
"branch_code":"MVPA",
"total_amt":1549500,
"product_details":[
{
"image":"CC250.jpg",
"cate":"Mobile Accessories"
},
{
"image":"CC256.jpg",
"cate":"Mobile Accessories"
}
]
}
]
const uniqueBranchCode = [...new Set(data.map(i => i.branch_code))]
const newData = uniqueBranchCode
.map(order => data.filter(orderSpecific => orderSpecific.branch_code === order))
.map(item => ({[item[0].branch_code]: item}))
console.log(newData)
You can try this way
const data =[{"order_id":"ORDCUTHIUJ","branch_code":"MVPA","total_amt":199500,"product_details":[{"image":"CC252.jpg","cate":"Mobile Accessories"}]},{"order_id":"ORHOGFD79L","branch_code":"PBVR","total_amt":325880,"product_details":[{"image":"1617382086515.jpg","cate":"Mobile Accessories"},{"image":"1617382322759.jpg","cate":"Mobile Accessories"},{"image":"CC251.jpg","cate":"Mobile Accessories"}]},{"order_id":"ORIYDJLYSJ","branch_code":"MVPA","total_amt":1549500,"product_details":[{"image":"CC250.jpg","cate":"Mobile Accessories"},{"image":"CC256.jpg","cate":"Mobile Accessories"}]}];
const result = data.reduce((acc, {order_id, branch_code, product_details}) => {
acc[branch_code] ??= {[branch_code]: []};
acc[branch_code][branch_code].push({order_id, product_details});
return acc;
}, {});
console.log(Object.values(result));
let obj = {}
function comp(x) {
const f1 = data.filter(function (i) {
return i.branch_code === x
})
return f1
}
for (let i = 0; i < data.length; i++) {
obj[`${data[i].branch_code}`] = comp(data[i].branch_code)
}
console.log(obj)

Categories