JavaScript modify Array of Objects and alter contained data - javascript

I am having difficulties formatting some data. Currently, I receive data in the following structure.
[
{
"q1":"5",
"q2":[
"13",
"12",
],
"q3":"test",
}
]
I essentially need to modify this or even create a new object, that takes the following structure.
[
{
id: 1, //q1
answers: [
{
answer: '5',
},
],
},
{
id: 2, //q2
answers: [
{
answer: '13',
},
{
answer: '12',
},
],
},
{
id: 3, //q3
answers: [
{
answer: 'test',
},
],
},
];
So the id in the above would be obtained by remove the q and getting the number in the first data object. It would then have an answers array that would have an object for each answer.
I have been attempting this but have gotten lost. I don't know if I should use loops, mapping, filters etc. To be honest, the furthest I have got so far is obtaining the keys
var modified = data.map(function(item) {
return Object.keys(item)
})
I have created a JSFiddle where I have been attempting to do this.
Is there any way I can achieve the data I am after?
Many thanks

Please use map function.
const data = {
"q1":"5",
"q2":[
"13",
"12",
],
"q3":"test",
};
const result = Object.keys(data).map(key => {
let item = {id: key.substring(1), answers: []};
if(typeof data[key] === "string")
item.answers.push({answer: data[key]});
else
item.answers = data[key].map(val => ({answer: val}));
return item;
});
console.log(result)

const inputData = [
{
"q1":"5",
"q2":[
"13",
"12",
],
"q3":"test",
}
]
function answerMapper(objVal, id){
return Array.isArray(objVal)
?
{ id, answers: objVal.map(answer => ({ answer }))}
:
{ id, answers: [{answer: objVal }] }
}
function formatObject(obj){
return Object.keys(obj).map((k, i) => answerMapper(obj[k], i+1));
}
const result = inputData.map(obj => formatObject(obj));
// remove flatMap if your inputData has more than one entry
console.log(result.flatMap(x => x));

map over the first element of the data with Object.entries, grab the key and value, create a new answers array and return a new object.
const data = [{
"q1": "5",
"q2": [
"13",
"12",
],
"q3": "test",
}];
const out = Object.entries(data[0]).map(obj => {
const [ key, value ] = obj;
const id = Number(key[1]);
// If the the value is an array
// return a new array of mapped data
// Otherwise return an array containing
// one object
const answers = Array.isArray(value)
? value.map(el => ({ answer: el }))
: [{ answer: value }];
// Return the new object
return { id, answers };
});
console.log(out);

lets create a pure function which accepts the object in the array like so
const processObject = obj => Object.keys(obj).map(id => {
const answer = obj[id];
const answers = Array.isArray(answer) ? answer : [answer]
const answerObjectArray = answers.map(ans => ({
answer: ans
}));
return {
id: +id.substring(1),
answers: answerObjectArray
}
});
const dataArray = [{
"q1": "5",
"q2": [
"13",
"12",
],
"q3": "test",
}];
const output = processObject(dataArray[0]);
console.log(output);

Related

If object set has an object property create an array

I have a response value which is dynamic which i need to store in redux state,
Response consist of array of object and and name
ex :
{data:[
{name:"abc",age:"10",id:"10"}
{name:"abc",age:"15",id:"20"}
{name:"def",age:"15",id:"20"}
]
name: "abc"
}
So if the name is same I need to create array with the name.
Expected :
abc:[
{name:"abc",age:"10",id:"10"}
{name:"abc",age:"15",id:"20"}
]
something I tried
data.map(function(o) {
if(data.name ==o.name)
return name[o];
});
If you're wanting a new object with a key of the name property you could try something like this
const response = {
data: [{
name: "abc",
age: "10",
id: "10"
},
{
name: "abc",
age: "15",
id: "20"
},
{
name: "def",
age: "15",
id: "20"
},
],
name: "abc"
}
const createSet = (someData) => {
let key = someData.name
let data = someData.data.filter(e => e.name === key)
return {
[key]: data
}
}
console.log(createSet(response))
You can extract duplicated using reduce and filter :
var data = {
data:[
{name:"abc",age:"10",id:"10"},
{name:"abc",age:"15",id:"20"},
{name:"def",age:"15",id:"20"}
],
name: "abc"
}
const lookup = data.data.reduce((a, e) => {
a[e.name] = ++a[e.name] || 0;
return a;
}, {});
console.log(data.data.filter(e => lookup[e.name]));

Check if an object in an array is exist in another array, then change the value of that another array in Javascript

i have an array A
const arrayA = [
{
id:a,
check:false
},
{
id:b,
check:false
},
{
id:c,
check:false
}
and an array B
const arrayB = [
{
id:a,
},
{
id:b,
}
]
and i want to check if arrayB is exist arrayA by id, then change check to true. Using lodash or js array methods
Hopefully I understood your question correctly but this is the solution I came up with.
arrayA.map((item) => ({ ...item, check: arrayB.some(({ id: idB }) => item.id === idB ) }))
You can use nested forEach loops, and check, if id matches then set check to true.
const arrayA = [{
id: "a",
check: false
},
{
id: "b",
check: false
},
{
id: "c",
check: false
}
]
const arrayB = [{
id: "a",
},
{
id: "b",
}
]
arrayB.forEach((b)=>{
arrayA.forEach((a)=>{
if(b.id == a.id){
a.check = true;
}
})
})
console.log(arrayA);
You could create an array containing the ids of arrayB and then check the objects in arrayA like
const arrayA = [
{
id: 'a',
check:false
},
{
id:'b',
check:false
},
{
id:'c',
check:false
} ];
const arrayB = [
{
id:'a',
},
{
id:'b',
}
];
const idsB = arrayB.map( obj => obj.id);
arrayA.forEach(obj => { if(idsB.indexOf(obj.id) > -1) obj.checked = true; } );
arrayA.forEach(obj => {console.log(JSON.stringify(obj))});
I could come up with this, which is not different than double loop, but may read easier.
arrayA.map((a) => {
a.check = arrayB.findIndex((b) => b.id === a.id) != -1;
return a;
});
Try this code it may help you
const arrayA = [
{id:'a',check:false},
{id:'b',check:false},
{id:'c',check:false}
]
const arrayB = [
{id:'a',},
{id:'b',}
]
arrayB.map(i => {
return i.check = arrayA.find(item => i.id == item.id)?.check;
});
console.log(arrayB)

How can I sort through an Axios response?

I am using Axios to execute a GET request to a public API, I need to combine the names if they are the same and add the values up to only show the top 20 (It's a large dataset) based on the highest to lowest amounts(ascending order).
Axios Response
[
{
name: "foo1",
value: "8123.30"
},
{
name: "foo1",
value: "2852.13"
},
{
name: "foo2",
value: "5132.23"
},
{
name: "foo1",
value: "1224.20"
},
{
name: "foo2",
value: "1285.23"
}
1200...
];
Expected Output
[
{ name: "foo1",
value: "12199.63" // from all combined "foo1" amounts in the dataset
},
{
name: "foo2",
value: "6417.46" // from all combined "foo2" amounts in the dataset
},
18..
]
I tried to do something like this....
const fetchData = () => {
return axios.get(url)
.then((response) => response.data)
};
function onlyWhatINeed() {
const newArr = []
return fetchData().then(data => {
const sortedData = data.sort((a, b) => parseFloat(a.value) - parseFloat(b.value));
// I need to loop through the dataset and add all the "values" up
// returning only the top 20 highest values in an array of those objects
newArr.push(sortedData)
})
}
But I am confused as to how to push this data to a new array of the sorted data (top 20 values in ascending order) and use this data in my web application. I am a bit new to creating REST APIs so if you could provide articles and/or resources so I can understand a little more that would be an awesome bonus!
You can combine the entries that share the same name using a map, then sort the map and keep the first twenty elements :
function onlyWhatINeed() {
const newArr = []
return fetchData().then(data => {
let map = new Map();
data.forEach(d => {
if(!map.has(d.name)) {
map.set(d.name, parseFloat(d.value));
} else {
map.set(d.name, map.get(d.name) + parseFloat(d.value));
}
})
return Array.from(map.entries()).sort((a, b) => a.value - b.value).slice(0, 20);
})
}
Since you're dealing with a large dataset, I recommend that you handle this server side instead of offloading the sorting to your clients.
async function fetchData(){
const { data } = await axios.get(url);
let newArr = []
data.forEach((e,i) => {
let index = newArr.findIndex(el => el.name === e.name);
if(index !== -1 ) newArr[index].value += parseFloat(e.value); //add to the value if an element is not unique
if(index === -1 ) newArr.push({...e, value: parseFloat(e.value)}); //push to the array if the element is unique and convert value to float
});
return newArr.sort((a,b) => a.value - b.value).slice(0,20);//returns an array of 20 elements after sorting
}
Please do more research on how to work with arrays and objects in general.
If you happen to already be using lodash, then here's a functional-style solution using lodash chaining. Probably not optimal performance, but could be useful for relatively small datasets.
const _ = require('lodash');
const data = [
{
name: "foo1",
value: "8123.30"
},
{
name: "foo1",
value: "2852.13"
},
{
name: "foo2",
value: "5132.23"
},
{
name: "foo1",
value: "1224.20"
},
{
name: "foo2",
value: "1285.23"
},
{
name: "foo3",
value: "1000.00"
},
{
name: "foo3",
value: "2000.00"
}
];
// 1. convert string values to floats
// 2. group by name
// 3. sum values by name
// 4. sort by descending value
// 5. take top 20
const output =
_(data)
.map(obj => ({
name: obj.name,
value: parseFloat(obj.value)
}))
.groupBy('name')
.map((objs, key) => ({
name: key,
value: _.sumBy(objs, 'value')
}))
.orderBy(['value'], 'desc')
.slice(0, 20)
.value();
console.log('output:', output);

Change particular key in nested array to object in javascript

If the fields key in a object is array, change the first value of arrays as a key value pair object in javascript.
var obj =
[
{ id:1, fields:["item", "2", "list"]},
{ id:2, fields:["sample", "1", "check"]}
]
function newObj(obj) {
let objFields = {};
modifiedObj.fields.forEach(field => objFields[field] = field);
modifiedObj.fields= objFields;
return modifiedObj;
}
var result = this.newObject(obj)
Expected Output
{
item: "item",
sample: "sample"
}
Try this:
var obj =
[
{ id:1, fields:["item", "2", "list"]},
{ id:2, fields:["sample", "1", "check"]}
]
function newObject(obj) {
let objFields = {};
obj.forEach(e => {
if(e.fields && e.fields.length>0)
objFields[e.fields[0]] = e.fields[0];
});
return objFields;
}
var result = this.newObject(obj);
console.log(result);
Here is a functional approach that makes use of Object.assign(), spread operator, and Array.map() to create the object you need.
const input = [
{ id: 1, fields: ["item", "2", "list"] },
{ id: 2, fields: ["sample", "1", "check"] }
];
const process = (input) => (Object.assign(...input.map(({ fields }) => (
fields.length ? { [fields[0]]: fields[0] } : {}
))));
console.log(process(input));
Your snippet was close, you just needed to clean up the variable names, and then using map makes it a bit neater too:
const obj = [
{id: 1, fields: ["item", "2", "list"]},
{id: 2, fields: ["sample", "1", "check"]}
]
function newObj(inputArray) {
let outputObject = {};
inputArray.map(item => item.fields[0])
.forEach(field => outputObject[field] = field);
return outputObject;
}
var result = newObj(obj)
console.log(result)

How to filter array of objects in javascript?

Here is my input :
const data = [
{ group: [{ label: "Can View" }, { label: "Can Create" }] },
{ topgroup: [{ label: "Can View" }, { label: "Can Create" }] },
{ emptyGorup: [] }
];
I am converting array of object to object by using this code
method 1 :
let permissions =
data &&
data.reduce((a, b) => {
const onlyKey = Object.keys(b)[0];
a[onlyKey] = b[onlyKey].map(i => i.value);
return a;
}, {});
//Output : {group:["can view","can create"],topgroup:["can view","can create"],emptygroup:[]}
My question is that I don't want to get object property if Object property is empty []. For example, In my output, I can see object property emptygroup is [].
{emptygroup:[]}.
My expected output will be if emptygroup is []
//Output : {group:["can view","can create"],topgroup:["can view","can create"]}
How can I do this ?
Try checking the length of the array
const permissionData = [
{ group: [{ label: "Can View" }, { label: "Can Create" }] },
{ topgroup: [{ label: "Can View" }, { label: "Can Create" }] },
{ emptyGorup: [] }
];
let permissions =
permissionData &&
permissionData.reduce((a, b) => {
const onlyKey = Object.keys(b)[0];
if(b[onlyKey].length) {
a[onlyKey] = b[onlyKey].map(i => i.label);
}
return a;
}, {});
console.log(permissions)
You can extend your current code. After you get the object you can filter out the key with empty array using filter and build object again from filtered values
let obj = {
group: ["can view"],
topgroup: ["can view", "can create"],
emptygroup: []
}
let finalObj = Object.fromEntries(Object.entries(obj).filter(([key, value]) => Array.isArray(value) && value.length))
console.log(finalObj)
You can add a condition in reduce:
let permissions =
permissionData &&
permissionData.reduce((a, b) => {
const onlyKey = Object.keys(b)[0];
if (a[onlyKey]) {
a[onlyKey] = b[onlyKey].map(i => i.value);
}
return a;
}, {});

Categories

Resources