Related
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
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 }
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);
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)) })))
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)