Below array is called Data, it's array of objects with keys like "marketValue"
Below array is called Columns, it's array of objects with each has Header (Pretty name for columns) and id (Ugly name for columns)
How to scroll through Data and update all ugly keys like this "marketValue" to "Market Value" using columns array?
This is how far I got, but it doesn't work, it returns undefined for every singe row:
let PrettyData = Data.map((row) =>
Object.entries(row).forEach(
(key) => {
let newKey = columns.filter((colRow) => colRow.id === key[0]);
let obj = {newKey: key[1]}
return obj;
}
)
);
If I understand correctly, you want to update the the keys of each object in data with the Header value of that columns object. This should do it:
const prettyMapping = {};
columns.forEach((column)=>{
prettyMapping[column.id] = column.Header
});
const PrettyData = Data.map((row)=>{
const prettyRow = {};
Object.keys(row).forEach((column)=>{
prettyRow[prettyMapping[column]] = row[column]
});
return prettyRow
});
Go through the columns and create a mapping of header to id.
Map over the rows. Map will create a new array with whatever is returned from each original row iteration
In each row iteration, create the newly formatted row using our mapping from before.
For this case:
const Data = [{qty:1, mp:2}, {qty:1, mp:2, mv:2}];
const columns = [{id:"qty",Header:'Quantity'}, {id:"mv",Header:'Market Value'}, {id:"mp",Header:'Market Price'}]
The above code returns:
[ { Quantity: 1, 'Market Price': 2 },
{ Quantity: 1, 'Market Price': 2, 'Market Value': 2 } ]
Hope this helps!
Related
I want to extract object keys into a single array and values in a different array so that I can paste the headers and values into a google sheet.
I want to achieve a dynamic code so that if more fields are pulled in from the API, it can map headers with values.
//API Response Sample.
var data = [
{
"actions": [
{
"action_type": "comment",
"value": "3"
},
{
"action_type": "like",
"value": "33"
},
{
"action_type": "link_click",
"value": "1531"
},
{
"action_type": "mobile_app_install",
"value": "1049"
}
],
"spend": "8621.03",
"date_start": "2017-10-28",
"date_stop": "2017-11-26"
}
]
So far the below code is fixed not dynamic.
const sheet = SpreadsheetApp.getActiveSheet();
//flatten the objects
var actionObjects = data.map(returnAction)
//get the headers
var headers = Object.keys(actionObjects[0])
//create a 2D array for rows
var actionRows = actionObjects.map(a => headers.map(h => a[h]))
//write the headers
sheet.getRange(sheet.getLastRow() + 1, 1, 1, headers[0].length).setValues([headers]);
//write the rows
sheet.getRange(sheet.getLastRow() + 1, 1, actionRows.length, actionRows[0].length).setValues(actionRows);
}
function returnAction(data){
let action = {}
data.actions.forEach(a => action[a.action_type] = a.value)
action ['spend'] = data.spend
action ['date_start'] = data.date_start
action ['date_stop'] = data.date_stop
return action
}
Object keys into array:
const keys = Object.keys(obj);
Object values into array:
const values = Object.values(obj);
Or both in one go ...
const keys = [];
const values = [];
for (const [key,value] of Object.entries(obj)) {
keys.push(key);
values.push(value);
}
If the structure of your object does not change... maybe something like this?
const action = {};
data.forEach(obj => {
for (const [key,value] of Object.entries(obj)) {
if (Array.isArray(value)) {
for (const o of value) {
const a = Object.values(o);
action[a[0]] = a[1];
}
} else action[key] = value;
}
})
Try this:
function setResult() {
const sheet = SpreadsheetApp.getActiveSheet();
class getResults {
constructor(arr) {
this.headers = {};
this.results = [];
for (const obj of arr) {
const actions = {};
for (const [header,value] of Object.entries(obj)) {
if (Array.isArray(value)) {
for (const action of value) {
const values = Object.values(action);
actions[values[0]] = values[1];
this.headers[values[0]] = values[0]
}
} else {
actions[header] = value;
this.headers[header] = header;
}
}
this.results.push(actions);
}
}
get array() {
const headers = Object.keys(this.headers);
const results = [headers];
for (const action of this.results) {
results.push(headers.map(header => !!action[header] ? action[header] : ''));
}
return results;
}
}
const values = new getResults(data).array;
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
This is a whole function which takes in the 'data' array-object and split it out onto your spreadesheet.
Explanation:
This function is mainly written in Object constructor and Classes.
more about object constructor in JavaScript
more about classes in JavaScript
According to your sample data, there are Objects inside an Array which I believe that each of those Objects are one set of data.
So, the 1st step is using a for ... of loop to work with each data set separately with this line of code for (const obj of arr) {}, this is very much the samething as the var actionObjects = data.map(returnAction) line in your original code. more about for ... of in JavaScript
With each of your data object, it has 2 main structure,
ONE is Array: Object: {Key1: Value1, Key2: Value2},
which you want Value1 as header and Value2 as the actual value in the output.
TWO is simply Key: Value pairs where you need key as the header and value as the value as output.
To work with the given slice of data set, this line for (const [header,value] of Object.entries(obj)) {} uses another for...of loop together with Object.entries() function to deconstruct the given Object into an 2D Array where each of the array value is one Array containing a pair of [key,value] form the given object. more about Object.entries()
Afterwards, if (Array.isArray(value)) {} will check each value given by the for...of Object.entries() function, if it is an Array, it met the condition ONE, else it is condition TWO.
For condition ONE, you want to use the 1st value of the object as header, and the 2nd value as actual value.
for (const action of value) {} iterate the 'values' of the object as an array, and store the values as {value[0]: value[1]} in the object declared before entering the loop fucntion for later use.
For condition TWO, just store it into the same object as condition ONE uses in the format of {key: value}.
At the end of each loop, before going onto the next data object, push the key: value pairs stored in this loop (named as actions) into result array.
Till this step, you alread have an array which looks like this:
Array: [
Object1: {
header1: value1,
header2: value2,
header3: value3,
header4: value4,
...
},
...
]
The Object this.header {} is declarated to keep track of the length of max header column counts, and get rip of any duplicates (since Object keys cannot be duplicated). This help keep the function working even if some of your data objects may has different headers from the others.
After these loops iterate every object inside your data Array,
custom method created with getter function get array() form the final result of all data into a 2D array for the apps script .setValues() function to print it onto your spreadsheet. more about getter
If your main concern is the class and object constructor, here is another version of code without using any of them:
function setResult2() {
const sheet = SpreadsheetApp.getActiveSheet();
const headers = {};
const results = [];
for (const obj of data) {
const actions = {};
for (const [header,value] of Object.entries(obj)) {
if (Array.isArray(value)) {
for (const action of value) {
const values = Object.values(action);
actions[values[0]] = values[1];
headers[values[0]] = values[0]
}
} else {
actions[header] = value;
headers[header] = header;
}
}
results.push(actions);
}
const getArray = (results,headers) => {
const headers_final = Object.keys(headers);
const results_final = [headers_final];
for (const action of results) {
results_final.push(headers_final.map(header => !!action[header] ? action[header] : ''));
}
return results_final;
}
const values = getArray(results,headers);
console.log(values)
sheet.getRange(sheet.getLastRow() + 1, 1, values.length, values[0].length).setValues(values);
}
I want to Update array of objects by another array of objects.
I have 2 array of objects like this:
const array = [
{id:'a',html:'',user:''},
{id:'b',html:'',user:''},
{id:'c',html:'',user:''},
];
const array_two = [
{id:'a',html:'',user:''},
{id:'b',html:'',user:''},
{id:'c',html:'',user:''},
{id:'d',html:'<p>Hello World</p>',user:'TEST USER'},
{id:'e',html:'<p>Hello World TWO</p>',user:'TEST USER TWO'},
];
and I want updateenter code here array by anotherArray
So my desired output is:
[
{id:'a',html:'<p>Hello World</p>',user:'TEST USER'},
{id:'b',html:'<p>Hello World TWO</p>',user:'TEST USER TWO'},
{id:'c',html:'',user:''},
];
Assuming (unlike your example) that you want objects with matching ids to update, here's how I would implement this:
Build an object byId mapping ids to corresponding object.
Loop through the updates and apply Object.assign to update the objects in-place, using byId to know which object to update.
const byId = {};
array.forEach((obj) => byId[obj.id] = obj);
array_two.forEach((obj) => {
if (!Object.hasOwnProperty(byId, obj.id)) {
// Create new object if id doesn't already exist.
byId[obj.id] = obj;
array.push(obj);
} else {
// Update existing object.
Object.assign(byId[obj.id], obj);
}
});
I have a nested array like following:
[
myfield: {value1,value2},
myotherfield: {value1,value2}
]
If i have the next scenario
[
myfield: {"A","B"},
myotherfield: {"C","D"}
]
How can i iterate the arrays to get the value1 of both fields at the same time? In this case i need to get A & C on the first iteration and B & D on the second iteration.
const data = {
myfield: ["A","B"],
myotherfield: ["C","D"]
};
data.myfield.forEach((fieldA, index) => {
const fieldB = data.myotherfield[index];
console.log(fieldA, fieldB);
})
Note1: Use this if both entries have the same length.
Note2: If both entries can have a different length then you need to check what of the two has the highest length while making the other entries return null.
const data = A.map((data_A, index) => {
const data_B = B[index]
console.log("data", data_A, data_B )
})
Hello JavaScript peers,
I have an array that was created from data from a csv file that looks like the following:
each array index for example array[0] are the headers in which there are 87 in this case. Every other array within that array are the rows.
I need to grab that data and split it between columns
the following code does just that but just for the first column:
var specialCounter = 0;
for(var j = 1; j<vm.lines.length; j++){
vm.columns.push(vm.lines[j][0]);
if(specialCounter >= vm.lines[j][0].length)
specialCounter = 0;
else
specialCounter++;
}
vm.columnData.columnData= vm.columns;
console.log(vm.columnData);
This is the array that it spits out.
How do I, do this for all of the columns in this array?
maybe with a structure like vm.dataPerColumn = [{column1: [...], column2: [...], etc...]
Reduce the array, forEach sub-array check if the key exists, and if not create the key on the result object (r). Push the current item to the key:
var arr = [['h1', 1, 2, 3], ['h2', 4 , 5 , 6], ['h3', 7, 8, 9]];
var result = arr.reduce(function(r, a) {
a.forEach(function(s, i) {
var key = i === 0 ? 'headers' : 'column' + i;
r[key] || (r[key] = []); // if key not found on result object, add the key with empty array as the value
r[key].push(s);
});
return r;
}, {});
console.log(result);
From reading the description and looking at the picture, it seems like the headers are in array[0]
const vm = {};
vm.lines = [["$", "house", "car"],[5, 10, 15],[25,35,45]];
const headers = vm.lines[0];
const data = vm.lines.slice(1);
const columns = data.reduce((newColumns, row) => {
for(let i=0;i<row.length;i++){
if(newColumns.length-1 < i){ //first column;
newColumns.push([]);
}
newColumns[i].push(row[i]);
}
return newColumns;
}, []);
const columnsWithHeaders = headers.map((header, index) => ({[header]:columns[index]}));
console.log(columnsWithHeaders);
You requested column1, column2 etc, but it doesn't really make sense when you already have an array, so i put the header name together with the respective column, then you can reference it directly
What i have done is to separate the headers and the data. So you don't have to worry about the first line,
Then i have converted the rows into columns, and after that you can just go through the headers and add the column array to each header.
I need to map an object of arrays. Once mapped I want to display the first row of content in a div. I have an object of arrays coming from the db and I'm only mapping 2 of the 4 arrays within the object.
What I want to be able to do is use the mapped arrays and then get all the data that corresponds with that mapped array and display it all in a div. The user can click an up or down arrow and then change what is displayed, but I'm having trouble getting it to show the next or prev data in the object. I have the clicking function properly set up (worked with test data) just think it's not working because I'm not mapping it correctly.
Original object coming from db:
object: {
PageNum: [array of items],
RowNum: [array of items],
CustomerName: [array of items],
FacilityName: [array of items]
}
mapping the arrays:
var delDS = [{
pageNum : delPageData["PageNum"],
rowNum : delPageData["RowNum"]
}];
var delMappedArray = delDS.map(function(obj) {
var rObj = {};
rObj[obj.pageNum] = obj.rowNum;
return rObj;
});
which returns something like this:
[object]
0: Object
2,2,4,4,6: Array(5)
0: "24"
1: "26"
2: "2"
3: "4"
4: "10"
length: 5
Try something like this:
//map the data
delPD = delPageData.PageNum.map((x,i) => ({
pageNum: x,
rowNum: delPageData["RowNum"][i],
cName: delPageData["CustomerName"][i],
fName: delPageData["FacilityName"][i],
}));
//sort the data
delPD.sort(function(a,b) {
if(a.pageNum == b.pageNum) {
return (a.rowNum - b.rowNum);
} else {
return (a.pageNum - b.pageNum);
}
});
//give the data an index number for ordering purposes later
for(var i=0; i<delPD.length; i++) {
delPD[i].index = i;
}
This is first mapping the array of objects and creating a new array. Then you are sorting the new array by page numbers and putting them in order. Then you're adding an index number to each object. This way you can use it later in your code if need be.
Hope this helps!