I have an array like this
[
{
"id": 1,
"name": "Personal Information",
"TabFields": [
{
"name": "First Name",
"field": {
"code": "personFirstName"
}
},
{
"name": "Gender",
"field": {
"code": "personGenderD"
}
},
{
"name": "Last Name",
"field": {
"code": "personLastName"
}
},
{
"name": "Mobile Number",
"field": {
"code": "mobileNumber"
}
},
{
"name": "Email Address",
"field": {
"code": "emailAddress"
}
}
]
}
]
What I need is to group the objects inside the TabFields to their respective TAB (PERSONAL_INFORMATION, CONTACT_DETAILS) by code value inside the field object
The object
"name": "First Name",
"field": {
"code": "personFirstName"
}
"name": "Gender",
"field": {
"code": "personGenderD"
}
"name": "Last Name",
"field": {
"code": "personLastName"
}
is belong to PERSONAL_INFORMATION and the object
"name": "Mobile Number",
"field": {
"code": "mobileNumber"
}
"name": "Email Address",
"field": {
"code": "emailAddress"
}
is belong to CONTACT_DETAILS. So the output would be
[
{
"id": 1,
"name": "Personal Information",
"TabFields": [
{
"label": "PERSONAL_INFORMATION",
"code": "PERSONAL_INFORMATION",
"fields": [
{
"name": "First Name",
"field": {
"code": "personFirstName"
}
},
{
"name": "Gender",
"field": {
"code": "personGenderD"
}
},
{
"name": "Last Name",
"field": {
"code": "personLastName"
}
}
]
},
{
"label": "CONTACT_DETAILS",
"code": "PERSONAL_INFORMATION",
"fields": [
{
"name": "Mobile Number",
"field": {
"code": "mobileNumber"
}
},
{
"name": "Email Address",
"field": {
"code": "emailAddress"
}
}
]
}
]
}
]
How to do it in javascript?
You can also do this with map:
var arr=[ { "id": 1, "name": "Personal Information", "TabFields": [ { "name": "First Name", "field": { "code": "personFirstName" } }, { "name": "Gender", "field": { "code": "personGenderD" } }, { "name": "Last Name", "field": { "code": "personLastName" } }, { "name": "Mobile Number", "field": { "code": "mobileNumber" } }, { "name": "Email Address", "field": { "code": "emailAddress" } } ] }];
personalContact = ["Mobile Number", "Email Address"];
result = arr.map(val=>{
personalInfo = { label:'personal', code:val.name, fields:val.TabFields.filter(k=>!personalContact.includes(k.name))};
contactInfo = { label:'contact', code:val.name, fields:val.TabFields.filter(k=>personalContact.includes(k.name))};
val.TabFields = [personalInfo, contactInfo];
return val;
});
console.log(result);
Idea would be to have an array which should distinguish between the contact details and personal details using which you can apply filter to get the data.
You can express transformations simply with a library I created, rubico.
const { pipe, fork, assign, get, map, filter } = require('rubico')
const PERSONAL_INFORMATION_FIELDS = new Set(['First Name', 'Gender', 'Last Name'])
const CONTACT_DETAILS_FIELDS = new Set(['Mobile Number', 'Email Address'])
// [datum] => [datum_with_grouped_TabFields]
const groupTabFields = assign({ // reassign TabFields to new grouped TabFields
TabFields: fork([
fork({
label: () => 'PERSONAL_INFORMATION',
code: () => 'PERSONAL_INFORMATION',
fields: pipe([
get('TabFields'), // datum => datum.TabFields
filter(pipe([ // FILTER: for each TabField of TabFields
get('name'), // TabField => TabField.name
field => PERSONAL_INFORMATION_FIELDS.has(field), // check if PERSONAL_INFORMATION_FIELDS has name
])),
]),
}),
fork({ // same as above but with contact details
label: () => 'CONTACT_DETAILS',
code: () => 'CONTACT_DETAILS',
fields: pipe([
get('TabFields'),
filter(pipe([
get('name'),
field => CONTACT_DETAILS_FIELDS.has(field)
])),
]),
}),
]),
})
x = map(groupTabFields)(data)
console.log(JSON.stringify(x, null, 2)) // output is what you wanted
I've added some comments, but for a deeper understanding of the library and code I've given you, I recommend reading the intuition and then reading the docs
Related
I'm trying to process the response data in the open dialog but got stuck in this the retrieval.
I followed the step by step procedure given in this link: https://developers.google.com/chat/how-tos/dialogs but unfortunately, it didn't work as well.
Here is the sample code:
My goal is to get the data from the dialog form then process it. My pain point is in the code: event.common.formInputs.firstnumber.stringInputs.value[0] where it returns undefined reading value.
function openDialog(event) {
return {
"action_response": {
"type": "DIALOG",
"dialog_action": {
"dialog": {
"body": {
"sections": [
{
"header": "Addition Calculator:",
"widgets": [
{
"textInput": {
"label": "First Number",
"type": "SINGLE_LINE",
"name": "firstnumber"
}
},
{
"textInput": {
"label": "Second Number",
"type": "SINGLE_LINE",
"name": "secondnumber"
}
},
{
"textInput": {
"label": "Third Number",
"type": "SINGLE_LINE",
"name": "thirdnumber"
}
},
{
"buttonList": {
"buttons": [
{
"text": "Submit",
"onClick": {
"action": {
"function": "giveAnswer"
}
}
}
]
},
"horizontalAlignment": "END"
}
]
}
]
}
}
}
}
};
}
function giveAnswer(event) {
var firstterm = parseFloat(event.common.formInputs.firstnumber.stringInputs.value[0])
var secondterm = parseFloat(event.common.formInputs.secondnumber.stringInputs.value[0])
var thirdterm = parseFloat(event.common.formInputs.thirdnumber.stringInputs.value[0])
var sum = firstterm+secondterm+thirdterm
return {
"cardsV2": [{
"cardId": "addContact",
"card": {
"header": {
"title": "The SUM is:",
"subtitle": "Answer",
"imageUrl": "https://images.emojiterra.com/google/noto-emoji/v2.034/128px/1f4f1.png",
"imageType": "SQUARE"
},
"sections": [
{
"widgets": [
{
"textParagraph": {
"text": sum
}
}
]
}
]
}
}
]
}
}
I tried the example in here but didn't work as well. https://developers.google.com/chat/how-tos/dialogs#receive_form_data_from_dialogs
I have the following example data that I'm trying to sort by multiple criteria:
details.length (from smaller to bigger)
details.type (alphabetically : Claimant, FellowPassenger)
If I sort it by details.length it seems to work but details.type doesn't both on multiple or single sorting criteria versions as data isn't sorted alphabetically (Claimant should appear first than Fellow).
So the output should be:
sortedByMultiple: [
{
"document_file_name": "4020672_FileName.pdf",
"details": [
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}
],
"state": "rejected"
},
{
"document_file_name": "4020890_FileName.pdf",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
}
],
"state": "rejected"
},
{
"document_file_name": "4020600_FileName.pdf",
"details": [
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
},
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
}
],
"state": "accepted"
}
]
const groupedStackOverflow = [
{
"document_file_name": "4020600_FileName.pdf",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
},
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}
],
"state": "accepted"
},
{
"document_file_name": "4020890_FileName.pdf",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
}
],
"state": "rejected"
},
{
"document_file_name": "4020672_FileName.pdf",
"details": [
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}
],
"state": "rejected"
}
]
console.log("groupedStackOverflow: ",groupedStackOverflow )
const sortedByMultiple = groupedStackOverflow.sort(function (a, b) {
return a.details.length - b.details.length || a.details.type - b.details.type ;
});
console.log("sortedByMultiple: ", sortedByMultiple);
const sortedByOne = groupedStackOverflow.sort(function (a, b) {
return a.details.type - b.details.type ;
});
console.log("sortedByOne: ", sortedByOne);
Try changing your sort condition using a string comparison because a.details.type - b.details.type returns NaN.
Try this:
const groupedStackOverflow = [
{
"document_file_name": "4020600_FileName.pdf",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
},
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}
],
"state": "accepted"
},
{
"document_file_name": "4020600_FileName.pdf",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
},
{
"id": 20656,
"type": "Dummy",
"name": "First Name Last Name"
}
],
"state": "accepted"
},
{
"document_file_name": "4020890_FileName.pdf",
"details": [
{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
}
],
"state": "rejected"
},
{
"document_file_name": "4020672_FileName.pdf",
"details": [
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}
],
"state": "rejected"
}
]
console.log("groupedStackOverflow: ",groupedStackOverflow )
const stringComparison = function (a,b) {
return a.type.localeCompare(b.type);
}
const sortedByMultiple = groupedStackOverflow.sort(function (a, b) {
if(a.details.length > 1) a.details.sort(stringComparison);
if(b.details.length > 1) b.details.sort(stringComparison);
return a.details.length - b.details.length || stringComparison(a.details[0],b.details[0]);
});
console.log("sortedByMultiple: ", sortedByMultiple);
You were also accessing type in the wrong way, details is an array and that's why it gives you an error. You can now modify that snippet to adjust it based on your needs
Firstly, We have sorted the array based on the details object length.
After that, we compared object details.type with the help of String.prototype.localeCompare() method for sorting the types.
const groupedStackOverflow = [{
"document_file_name": "4020600_FileName.pdf",
"details": [{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
},
{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}
],
"state": "accepted"
},
{
"document_file_name": "4020890_FileName.pdf",
"details": [{
"id": 10000,
"type": "Fellow",
"name": "Fellow First Name Last Name"
}],
"state": "rejected"
},
{
"document_file_name": "4020672_FileName.pdf",
"details": [{
"id": 20656,
"type": "Claimant",
"name": "First Name Last Name"
}],
"state": "rejected"
}
]
// sorting based upon index
const sortedByLength = groupedStackOverflow.sort((a, b) => {
return a.details.length - b.details.length;
});
// sorting based upon details type alphbatically
const finalSorted = groupedStackOverflow.map(item => {
if (item.details.length > 1) {
return item.details.sort((a, b) => {
// we are using localeCompare() method to sort details.type
return (a.type).localeCompare(b.type);
});
} else {
return item;
}
})
console.log(finalSorted);
I am trying to the values from my data.json which consists of array of objects. I am trying to get the values by using map method on json data. My Json dat structure is like Array->Object->Array-Object([{[{}]}]). This is how the data is structured in Json. I have written down the Json data and logic to get the values down. Whenever I am trying to get the values from (inner array of object) I am ending up with undefined. Any one could assist me how to resolve this issue. Thanks in advance!
[
{
"key": "row-0",
"cells": [
{
"key": "cell-0",
"id": "ID-0",
"headerName": "Name",
"CustomerName": "ABC"
},
{
"key": "cell-1",
"id": "ID-1",
"headerName": "RegID",
"CustomerID": "P-01"
},
{
"key": "cell-2",
"id": "ID-2",
"headerName": "Detail",
"Deatil": "Abc"
}
]
},
{
"key": "row-1",
"cells": [
{
"key": "cell-1",
"id": "ID-1",
"headerName": "Name",
"CustomerName": "CDE"
},
{
"key": "cell-2",
"id": "ID-2",
"headerName": "RegID",
"CustomerID": "P-02"
},
{
"key": "cell-3",
"id": "ID-3",
"headerName": "Detail",
"Deatil": "CDE"
}
]
}
]
//Logic
{mockData.map((values, index) => {
console.log("VALUES", values);
return values.cells.map(({ headerName, ...rest }) => {
console.log("JSON", JSON.stringify(rest));
console.log("REST", rest.CustomerName);---> getting undefined(I tried many approach everything is giving me undefined)
});
})}
I have created an example for you
As mentioned in the above comment.. elements without customerName will give undefined.
let mockData = [{
"key": "row-0",
"cells": [{
"key": "cell-0",
"id": "ID-0",
"headerName": "Name",
"CustomerName": "ABC"
},
{
"key": "cell-1",
"id": "ID-1",
"headerName": "RegID",
"CustomerID": "P-01"
},
{
"key": "cell-2",
"id": "ID-2",
"headerName": "Detail",
"Deatil": "Abc"
}
]
},
{
"key": "row-1",
"cells": [{
"key": "cell-1",
"id": "ID-1",
"headerName": "Name",
"CustomerName": "CDE"
},
{
"key": "cell-2",
"id": "ID-2",
"headerName": "RegID",
"CustomerID": "P-02"
},
{
"key": "cell-3",
"id": "ID-3",
"headerName": "Detail",
"Deatil": "CDE"
}
]
}
];
mockData.map((values, index) => {
console.log("VALUES", values);
return values.cells.map(({
headerName,
...rest
}) => {
console.log("JSON",rest);
console.log("Key:", rest.key);
console.log("ID:", rest.id);
console.log("CustomerName:", rest.CustomerName ? rest.CustomerName : 'NA' );
});
})
I have an array. The elements in the array represent the menu elements. I want to create "breadcrumb" according to the menu item I selected. However, it provides errors dynamically after 3 depth while working.
// My Array
const menuArray = [{
"label": "Dashboard"
},
{
"label": "Products",
"items": [{
"label": "All Products"
},
{
"label": "New Product"
},
{
"label": "Product Categories"
}
]
},
{
"label": "Posts",
"items": [{
"label": "All Posts"
},
{
"label": "New Post"
},
{
"label": "Post Categories"
}
]
},
{
"label": "Sliders"
},
{
"label": "Settings",
"items": [{
"label": "General Settings"
},
{
"label": "User",
"items": [{
"label": "Your Profile"
},
{
"label": "Edit Profile"
}
]
},
{
"label": "Social Settings"
},
{
"label": "Link Settings"
}
]
}
];
// The function I experiment with
writeParent(event, arr) {
let ct = 0;
let found = false;
let parentsLine = [];
arr.some((e) => {
parentsLine = [];
let curr = e;
for (curr; curr.items != null; curr = curr.items[0]) {
if (event.label == curr.label) {
found = true;
return true;
}
parentsLine.push(curr.label);
}
if (event.label == curr.label) {
found = true;
return true;
}
});
if (found) {
return parentsLine;
} else {
return 'ERR: elm not found';
}
}
console.log(writeParent({
"label": "Edit Profile"
}, menuArray));
For example, if the element I selected is;
{
"label": "New Post"
}
I want to get;
[
{
"label": "Posts"
},
{
"label": "New Post"
}
]
or
if the element I selected is;
{
"label": "Edit Profile"
}
I want to get;
[
{
"label": "Settings"
},
{
"label": "User"
},
{
"label": "Edit Profile"
}
]
I didn't know how to find the parent of the selected element. How can I do that?
I've solved the problem.
menuArray = [{
"label": "Dashboard"
},
{
"label": "Products",
"items": [{
"label": "All Products"
},
{
"label": "New Product"
},
{
"label": "Product Categories"
}
]
},
{
"label": "Posts",
"items": [{
"label": "All Posts"
},
{
"label": "New Post"
},
{
"label": "Post Categories"
}
]
},
{
"label": "Sliders"
},
{
"label": "Settings",
"items": [{
"label": "General Settings"
},
{
"label": "User",
"items": [{
"label": "Your Profile"
},
{
"label": "Edit Profile"
}
]
},
{
"label": "Social Settings"
},
{
"label": "Link Settings"
}
]
}
];
function find(array, event) {
if (typeof array != 'undefined') {
for (let i = 0; i < array.length; i++) {
if (array[i].label == event.label) return [event.label];
let a = this.find(array[i].items, event);
if (a != null) {
a.unshift(array[i].label);
return a;
}
}
}
return null;
}
console.log(find(menuArray, { "label": "Edit Profile" }));
Check for the decimal id and group them accordingly.
Below are the sample and recommended JSON's
Sample JSON
{
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
Would like to iterate and Re-structure the above JSON into below recommended format.
Logic: Should check the id(with and without decimals) and group them based on the number.
For Example:
1, 1.1, 1.2.3, 1.4.5 => data1: [{id: 1},{id: 1.1}....]
2, 2.3, 2.3.4 => data2: [{id: 2},{id: 2.3}....]
3, 3.1 => data3: [{id: 3},{id: 3.1}]
Recommended JSON
{
"results": [
{
"data1": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
}
]
},
{
"data2": [
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
}
]
},
{
"data3": [
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
}
]
},
{
"data4": [
{
"name": "Download",
"id": "4.2"
}
]
}
]
}
I have tried the below solution but it doesn't group the object
var formatedJSON = [];
results.map(function(d,i) {
formatedJSON.push({
[data+i]: d
})
});
Thanks in advance.
You can use reduce like this. The idea is to create a key-value pair for each data1, data2 etc so that values in this object are the values you need in the final array. Then use Object.values to get those as an array.
const sampleJson = {"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]}
const grouped = sampleJson.results.reduce((a, v) => {
const key = `data${parseInt(v.id)}`;
(a[key] = a[key] || {[key]: []})[key].push(v);
return a;
},{});
console.log({results: Object.values(grouped)})
One liner / Code-golf:
let s={"results":[{"name":"Download","id":"1.1.1"},{"name":"Download","id":"1.2"},{"name":"Download","id":"1.3.2"},{"name":"Download","id":"2"},{"name":"Download","id":"2.3"},{"name":"Download","id":"3.2"},{"name":"Download","id":"3.5"},{"name":"Download","id":"4.2"}]},k;
console.log({results:Object.values(s.results.reduce((a,v)=>(k=`data${parseInt(v.id)}`,(a[k] = a[k]||{[k]:[]})[k].push(v),a),{}))})
Here you go:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
let newSet = new Set();
data.results.forEach(e => {
let key = e.id.substring(0, e.id.indexOf('.'));
console.log(key);
if (newSet.has(key) == false) {
newSet.add(key);
newSet[key] = [];
}
newSet[key].push(e.id);
});
console.log(newSet);
Here's how you'd do it:
var data = {
"results": [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
};
var newData = {
"results": {}
};
data.results.forEach(item => {
var num = item.id.slice(0, 1);
if (newData.results["data" + num]) {
newData.results["data" + num].push(item);
} else {
newData.results["data" + num] = [item];
}
})
data = newData;
console.log(data);
What this does is it iterates through each item in results, gets the number at the front of this item's id, and checks if an array of the name data-{num} exists. If the array exists, it's pushed. If it doesn't exist, it's created with the item.
let input = getInput();
let output = input.reduce((acc, curr)=>{
let {id} = curr;
let majorVersion = 'name' + id.split('.')[0];
if(!acc[majorVersion]) acc[majorVersion]= [];
acc[majorVersion].push(curr);
return acc;
},{})
console.log(output)
function getInput(){
return [
{
"name": "Download",
"id": "1.1.1"
},
{
"name": "Download",
"id": "1.2"
},
{
"name": "Download",
"id": "1.3.2"
},
{
"name": "Download",
"id": "2"
},
{
"name": "Download",
"id": "2.3"
},
{
"name": "Download",
"id": "3.2"
},
{
"name": "Download",
"id": "3.5"
},
{
"name": "Download",
"id": "4.2"
}
]
}
One solution with RegEx for finer control as it would differentiate easily between 1 and 11.
Also this will make sure that even if the same version comes in end(say 1.9 in end) it will put it back in data1.
let newArr2 = ({ results }) =>
results.reduce((acc, item) => {
let key = "data" + /^(\d+)\.?.*/.exec(item.id)[1];
let found = acc.find(i => key in i);
found ? found[key].push(item) : acc.push({ [key]: [item] });
return acc;
}, []);