The quiz is implemented in such a way that questions are displayed depending on the user's choice. I need to implement the testing functionality of the questionnaire. After passing in the console should have the same structure as I have provided below. Now my script produces a slightly different structure, not the same as in the example. Example of my code:
const questions = [
{
id: "1",
question: "q1",
answer_1: {
text: "a1",
next_question: "2",
},
answer_2: {
text: "a2",
next_question: "3",
},
},
{
id: "2",
question: "q2",
answer_1: {
text: "a1/a2",
next_question: "",
},
},
{
id: "3",
question: "q3",
answer_1: {
text: "a1",
next_question: "",
},
answer_2: {
text: "a2",
next_question: "4",
},
},
{
id: "4",
question: "q4",
answer_1: {
text: "a1/a2",
next_question: "",
},
},
];
const newQuestionObj = {};
const getAllPath = (arr) => {
const treeStructure = arr.forEach((item) => {
newQuestionObj[item.id] = {
...item,
children: [
...Object.keys(item)
.filter((k) => k.includes("answer"))
.map((k) => ({ ...item[k] })),
],
};
});
const createBranches = ({ question, children }) =>
children.map(({ text, next_question }) =>
next_question.length === 0
? { [question]: text }
: createBranches(newQuestionObj[next_question]).map((obj) => ({
[question]: text,
...obj,
}))
);
return createBranches(newQuestionObj[arr[0].id]);
};
let result = {
path: {
list: getAllPath(questions),
},
};
console.log(result);
Desired result to get:
{
"paths":{
"list":[
[
{
"q1":"a1"
},
{
"q2":"a1/a2"
}
],
[
{
"q1":"a2"
},
{
"q3":"a1"
}
],
[
{
"q1":"a2"
},
{
"q3":"a2"
},
{
"q4":"a1/a2"
}
]
]
}
}
Related
Hi all I have following data:
const section = {
fileds: [
{ id: "some Id-1", type: "user-1" },
{
child: [
{ id: "some Id-2", type: "user-2" },
{ fileds: [{ id: "kxf5", status: "pending" }] },
{ fileds: [{ id: "ed5t", status: "done" }] }
]
},
{
child: [
{ id: "some Id-3", type: "teacher" },
{ fileds: [{ id: "ccfr", status: null }] },
{ fileds: [{ id: "kdpt8", status: "inProgress" }] }
]
}
]
};
and following code:
const getLastIds = (arr) =>
arr.flatMap((obj) => {
const arrayArrs = Object.values(obj).filter((v) => Array.isArray(v));
const arrayVals = Object.entries(obj)
.filter(([k, v]) => typeof v === "string" && k === "id")
.map(([k, v]) => v);
return [...arrayVals, ...arrayArrs.flatMap((arr) => getLastIds(arr))];
});
console.log(getLastIds(section.fileds));
// output is (7) ["some Id-1", "some Id-2", "kxf5", "ed5t", "some Id-3", "ccfr", "kdpt8"]
My code doing following, it printing in new array all ids.
It's working but I don't need all ids.
I need to return only last id in array and I should use recursion.
The output should be
(4) [" "kxf5", "ed5t", "ccfr", "kdpt8"]
P.S. here is my code in codesandbox
Is there a way to solve this problem with recursion? Please help to fix this.
You can do it with reduce.
function getLastIds (value) {
return value.reduce((prev, cur) => {
if (cur.id) {
return [ ...prev, cur.id ];
} else {
let key = ('child' in cur) ? 'child' : 'fileds';
return [ ...prev, ...getLastIds (cur[key]) ]
}
}, []);
}
You could check if a certain key exists and take this property for mapping id if status exists.
const
getValues = data => {
const array = Object.values(data).find(Array.isArray);
return array
? array.flatMap(getValues)
: 'status' in data ? data.id : [];
},
section = { fileds: [{ id: "some Id-1", type: "user-1" }, { child: [{ id: "some Id-2", type: "user-2" }, { fileds: [{ id: "kxf5", status: "pending" }] }, { fileds: [{ id: "ed5t", status: "done" }] }] }, { child: [{ id: "some Id-3", type: "teacher" }, { fileds: [{ id: "ccfr", status: null }] }, { fileds: [{ id: "kdpt8", status: "inProgress" }] }] }] },
result = getValues(section);
console.log(result);
I have this object:
var x= {
"data": {
"getLand": {
"id": "xxx",
"bid": [{
"result": "ON",
"buyer": {
"username": "Dis"
},
"offerSet": [{
"createdStr": "202",
"value": 1
}]
},
{
"result": "CANCEL",
"buyer": {
"username": "Dis"
},
"offerSet": [{
"createdStr": "202",
"value": 15
}]
}
]
}
}
}
How can i know is result === "ON" && username == "Dis" ?
I tried with this:
for (var key in x.data.getLand.bid) {
if((x.data.getLand.bid[key].result === 'ON') && (x.data.getLand.bid[key].buyer.username.toUpperCase() === 'DIS')){
console.log(x.data.getLand.bid[key]);
}
}
it gives me some problems .... sometimes it works and sometimes it doesn't. Would you be kind enough to show me another way?
You can utilize the ES6 array function forEach to loop through the array items.
const x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 1, }, ], }, { result: "CANCEL", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 15, }, ], }, ], }, }, }
const bidList = x.data.getLand.bid
bidList.forEach((bid, index) => {
if (bid.result === 'ON' && bid.buyer.username.toUpperCase() === 'DIS') console.log(index, bid)
})
You can do this with filter and forEach loop.
like this:
var x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis" }, offerSet: [{ createdStr: "202", value: 1 }] }, { result: "CANCEL", buyer: { username: "Dis" }, offerSet: [{ createdStr: "202", value: 15 }] } ] } } };
x.data.getLand.bid
.filter(
({ result, buyer: { username } }) => result === "ON" || username === "Dis"
)
.forEach((el, id) => console.log(el, id));
An example with for...of
var x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 1, }, ], }, { result: "CANCEL", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 15, }, ], }, ], }, }, };
for (const item of x.data.getLand.bid) {
if (item.result === "ON" && item.buyer.username.toUpperCase() === "DIS") {
console.log(item);
}
}
Edit:
If you need the index, you can use forEach.
var x = { data: { getLand: { id: "xxx", bid: [ { result: "ON", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 1, }, ], }, { result: "CANCEL", buyer: { username: "Dis", }, offerSet: [ { createdStr: "202", value: 15, }, ], }, ], }, }, };
x.data.getLand.bid.forEach((item, i) => {
if (item.result === "ON" && item.buyer.username.toUpperCase() === "DIS") {
console.log(i);
console.log(item);
}
});
This is my output:
const data = {
item : {
id: "1",
name: "aa",
group: [
{
id:"11",
order:0,
},
{
id:"33",
order:5,
},
{
id:"3",
order:1,
},
]
},
item2 : {
id: "2",
name: "aaa",
group: [
{
id:"111",
order:3,
},
{
id:"33",
order:1,
},
{
id:"3",
order:2,
},
]
}
}
I want to order my group object by order item. If it was an object, I could do it:
data.group.sort((a, b) => {
return a.order - b.order || a.order.localeCompare(b.order);
});
But it will override the elements and I will get only the lastest item. I believe that something else is missing to make it work the way I want.
This is the desired output:
const data = {
item : {
id: "1",
name: "aa",
group: [
{
id:"11",
order:0,
},
{
id:"3",
order:1,
},
{
id:"33",
order:5,
},
]
},
item2 : {
id: "2",
name: "aaa",
group: [
{
id:"33",
order:1,
},
{
id:"3",
order:2,
},
{
id:"111",
order:3,
},
]
}
}
How can i do that?
Try this code:
const data = {
item : {
id: "1",
name: "aa",
group: [
{
id:"11",
order:0,
},
{
id:"33",
order:5,
},
{
id:"3",
order:1,
},
]
},
item2 : {
id: "2",
name: "aaa",
group: [
{
id:"111",
order:3,
},
{
id:"33",
order:1,
},
{
id:"3",
order:2,
},
]
}
}
Object.keys(data).forEach(key => {
const item = data[key];
item.group = item.group.sort((a, b) => {
return a.order - b.order || a.order.localeCompare(b.order);
});
return item;
});
console.log(data);
Do this (CREDIT TO: flymaster)
Object.keys(dataINPT).forEach(key => {
const your = dataINPT[key];
your.group = your.group.sort((some, some2) => {
return some.order - some2.order || some.order.localeCompare(some2.order);
});
return your;
});
console.log(data);
Use the Object.values, forEach loop and apply sort.
Object.values(data).forEach(({ group }) =>
group.sort((a, b) => {
return a.order - b.order || a.order.localeCompare(b.order);
})
);
const data = {
item: {
id: "1",
name: "aa",
group: [
{
id: "11",
order: 0,
},
{
id: "33",
order: 5,
},
{
id: "3",
order: 1,
},
],
},
item2: {
id: "2",
name: "aaa",
group: [
{
id: "111",
order: 3,
},
{
id: "33",
order: 1,
},
{
id: "3",
order: 2,
},
],
},
};
Object.values(data).forEach(({ group }) =>
group.sort((a, b) => {
return a.order - b.order || a.order.localeCompare(b.order);
})
);
console.log(data);
I have got two arrays of objects. I want to filter data based on PermissionObj.
This is coming from database. Here are arrays of sub-arrays in the permissionObj.
const PermissionObj = {
permission: [
{
books: [
{
label: "Can View",
value: "can_view"
}
]
},
{
Journals: [
{
label: "Can View",
value: "can_view"
},
{
label: "Can Create",
value: "can_create"
}
]
},
{
deal: [
{
label: "Can update",
value: "can_update"
},
{
label: "Can delete",
value: "can_delete"
}
]
}
]
}
this is static data. I want to compare this data based on PermissionObj.
const data = [
{
label: "books",
value: "can_view"
},
{
label: "deal",
content: [
{
value: "can_update"
},
{
value: "can_delete"
},
{ value: "can_view" }
]
},
{
label: "Articles"
},
{
label: "Journals",
content: [
{
value: "can_create"
},
{
value: "can_view"
},
{
value: "can_delete"
},
{
value: "can_edit"
}
]
}
]
I am trying to filter the data array of the object based on PermissionObj array of objects. here is my trying code.
const permKeys = PermissionObj.permission.flatMap(item => Object.keys(item));
const filteredData = data.filter(({ label }) => permKeys.includes(label));
console.log(filteredData);
Here is my problem, I have been faced is that I don't want to get can_edit, can_delete if it doesn't match with permission objects in journals. In my permission objects, There is no can_edit and can_delete in journals.
My accepted Output would be this format :
const data = [
{
label: "books",
value: "can_view"
},
{
label: "deal",
content: [
{
value: "can_update"
},
{
value: "can_delete"
}
]
},
{
label: "Journals",
content: [
{
value: "can_create"
},
{
value: "can_view"
}
]
}
]
It is possible to use reduce method and apply logic to decide what data should be pushed:
const result = data.reduce((a, c) => {
let filterObj = PermissionObj.permission.find(f => f[c.label]);
if (filterObj) {
if (c.value) {
a.push(c);
}
if (c.content) {
c.content = c.content.filter(f => filterObj[c.label]
.some(s => s.value.toLowerCase() == f.value.toLowerCase()));
a.push(c);
}
}
return a;
},[])
An example:
const PermissionObj = {
permission: [
{
"books": [
{
"label": "Can View",
"value": "can_view"
}
]
},
{
"Journals": [
{
"label": "Can View",
"value": "can_view"
},
{
"label": "Can Create",
"value": "can_create"
}
]
},
{
"deal": [
{
"label": "Can update",
"value": "can_update"
},
{
"label": "Can delete",
"value": "can_delete"
}
]
}
]
};
const data = [
{
label: "books",
value: "can_view"
},
{
label: "deal",
content: [
{
value: "can_update"
},
{
value: "can_delete"
},
{
value:"can_view"
}
]
},
{
label: "Articles",
},
{
label: "Journals",
content: [
{
value: "can_create"
},
{
value: "can_view"
},
{
value: "can_delete"
},
{
value: "can_edit"
}
]
}
];
const result = data.reduce((a, c) => {
let filterObj = PermissionObj.permission.find(f => f[c.label]);
if (filterObj) {
if (c.value) {
a.push(c);
}
if (c.content) {
c.content = c.content.filter(f => filterObj[c.label].some(s => s.value.toLowerCase() == f.value.toLowerCase()));
a.push(c);
}
}
return a;
},[])
console.log(result);
Given an array in this format:
[
[{
name: "name",
value: "My-name"
},
{
name: "qty",
value: "1"
},
{
name: "url",
value: "test.com"
},
{
name: "comment",
value: "my-comment"
}
],
[{
name: "name",
value: "My-name2"
},
{
name: "qty",
value: "3"
},
{
name: "url",
value: "test2.com"
}
],
[{
name: "name",
value: "My-name3"
},
{
name: "qty",
value: "1"
},
{
name: "url",
value: "test3.com"
},
{
name: "comment",
value: "my-comment3"
}
]
]
I'm looking to switch that to:
[
[
{ name: "My-name" },
{ qty: "1" },
{ url: "test.com" },
{ comment: "my-comment", }
],[
{ name: "My-name2" },
{ qty: "3" },
{ url: "test2.com",
],[
{ name: "My-name3", },
{ qty: "1", },
{ url: "test3.com", },
{ comment: "my-comment3", }
]
]
In other words, swapping out the array keys but maintaining the object structure within each array element.
I've tried looping over each element and can swap the keys out using something like:
newArray[iCount][item.name] = item.value;
However I'm then struggling to preserve the object order. Note that the comment field may or may not appear in the object.
With Array.map() function:
var arr = [
[{name:"name",value:"My-name"},{name:"qty",value:"1"},{name:"url",value:"test.com"},{name:"comment",value:"my-comment"}],
[{name:"name",value:"My-name2"},{name:"qty",value:"3"},{name:"url",value:"test2.com"}],
[{name:"name",value:"My-name3"},{name:"qty",value:"1"},{name:"url",value:"test3.com"},{name:"comment",value:"my-comment3"}]
],
result = arr.map(function(a){
return a.map(function(obj){
var o = {};
o[obj.name] = obj.value
return o;
});
});
console.log(result);
Check my moreBetterOutput value. I think will be better.
If you still need a result like your example in the question then you can check output value.
const input = [
[
{
name:"name",
value:"My-name"
},
{
name:"qty",
value:"1"
},
{
name:"url",
value:"test.com"
},
{
name:"comment",
value:"my-comment"
}
],
[
{
name:"name",
value:"My-name2"
},
{
name:"qty",
value:"3"
},
{
name:"url",
value:"test2.com"
}
],
[
{
name:"name",
value:"My-name3"
},
{
name:"qty",
value:"1"
},
{
name:"url",
value:"test3.com"
},
{
name:"comment",
value:"my-comment3"
}
]
]
const output = input.map(arr => arr.map(obj => ({[obj.name]: obj.value})))
const moreBetterOutput = output.map(arr => arr.reduce((acc, item, index) => {
acc[Object.keys(item)[0]] = item[Object.keys(item)[0]];
return acc;
}, {}) )
//console.log(output);
console.log(moreBetterOutput);
Another map function:
const result = array.map( subarray =>
Object.assign(...subarray.map( ({name, value}) => ({ [name] : value }) ))
);