I have a JavaScript array of data, which currently looks like this
2021-09-01 00:10:00,11,10,'John',23
2021-09-01 13:20:00,12,20,'Sarah',55
2021-09-01 18:50:00,34,5,'Garry',12
2021-09-02 09:01:00,22,40,'Vicki',53
2021-09-02 14:23:00,34,2,'Peter',123
2021-09-02 16:20:00,21,10,'Victor',03
2021-09-02 18:00:00,88,40,'Nelly',3
You will notice that the first part is a date, for example "2021-09-01 00:10:00"
How can I create a new javascript array from that data which groups the rows by date, so in my example it would be 2 rows
2021-09-01
2021-09-02
And then add up the 3rd comma-separated value of each row (the values just before the persons name), so in my example it would output
2021-09-01,35
2021-09-02,92
And then give a total number of rows found for each group (there are 3 rows for 2021-09-01 and 4 rows for 2021-09-02)
2021-09-01,35,3
2021-09-02,92,4
Then return an average for each row (for example, first row = 35 / 3 = 11.66)
2021-09-01,35,3,11.66
2021-09-02,92,4,23
I then want to do a bit of maths on each row, but hopefully I can figure that out
Is this at all possible?
This would be a big help if anyone has an idea
Thank you
==================
WOW thank you everyone for your suggestions, maybe I was a little confused by saying it was an array, but when I did a console.log of my "sampledata" data, it was showing it as array
I'm basically using this, and want to run my original question on the sampledata output
d3.queue()
.defer(d3.csv, "test.csv")
.await(function(error, sampledata)
{
if (error) throw error;
console.log(sampledata);
});
if this helps
I like reduce for this
const csv = `2021-09-01 00:10:00,11,10,'John',23
2021-09-01 13:20:00,12,20,'Sarah',55
2021-09-01 18:50:00,34,5,'Garry',12
2021-09-02 09:01:00,22,40,'Vicki',53
2021-09-02 14:23:00,34,2,'Peter',123
2021-09-02 16:20:00,21,10,'Victor',03
2021-09-02 18:00:00,88,40,'Nelly',3`;
const arr = csv.split("\n"); // split the csv on newline
const res = arr.reduce((acc,cur) => {
let [date,ignore,num] = cur.split(","); // regex is needed if there are quoted commas before the interesting data
date = date.split(" ")[0]; // take the date part
acc[date] = acc[date] || {sum:0,cnt:0, avg:0 }; // reuse if existing, create new if not
acc[date].sum += +num;
acc[date].cnt++;
acc[date].avg = +(acc[date].sum/acc[date].cnt).toFixed(2); // remove decimals more than 2
return acc
},{})
console.log(res)
First, you'll need to create an object to map dates to their respective values, then, you'll iterate over your array in groups of 5.
const itemsByDate = {};
for (let i = 0; i < items.length; i += 5) {
const date = items[i].toISOString().slice(0, 10);
const value = items[i + 2];
if (!itemsByDate[date]) {
itemsByDate[date] = {
value,
count: 1
}
}
else {
itemsByDate[date].value += value;
itemsByDate[date].count += 1;
}
}
Then you iterate over the values of itemsByDate and calculate the average
for (const item of Object.values(itemsByDate)) {
item.mean = item.value / item.count;
}
If you really want to restructure your data as an array again, which I don't think is a good idea if you want to treat that data with javascript, you can do that with
const myArray = Object.entries(itemsByDate).flatMap(([date, item]) => {
return [date, item.value, item.count, item.mean];
});
Related
Building a script in google apps script.
I get values from an invoice data sheet with multiple lines per invoice so as to account for line items.
My progress so far has been to extract individual invoice numbers from the column (each invoice number occurs as many line items the individual invoice has).
The array todaysInvoices looks like this: [35033817, 35033818, 35033819, 35033820, 35033821]
Now, I need a way to create an object for each of these invoice numbers that has different properties (such as invoiceDate and customerName etc.). The initial invoice number as in the array should thereby be assigned as 'id' property to the new invoice object.
I need help to use objects in javascript.
If you require additional information, please let me know.
Below is a screenshot of a simplified version of my order sheet:
This is a clipping of my order sheet. Before and after the shown columns there are many more with more details but the hierarchies of information are already in the image
Below is the code I have so far:
const orderSheet = SpreadsheetApp.openById('SPREADSHEETID').getSheetByName('SHEETNAME');
const invoiceTemplate = DriveApp.getFileById('DOCUMENTID');
const tempFolder = DriveApp.getFolderById('FOLDERID');
const invoiceData = orderSheet.getRange(4,7, orderSheet.getLastRow() - 1, 57).getDisplayValues().filter(function (rows){ return rows[0] === 'INVOICED'});
const invDataRepo = SpreadsheetApp.openById('SPREADSHEETID2');
var timestamp = new Date();
function printBulkInvoices() {
logLineItems ();
var todaysInvoices = uniqueInvIDs ();
todaysInvoices.sort();
todaysInvoices.map(String);
//fetchInvData (todaysInvoices);
Logger.log (todaysInvoices)
}
function fetchInvData (invoiceIDs) {
let invoices = {
}
Logger.log(invoices)
invoiceIDs.forEach
}
function fetchLineItems (invoiceDataArray) {
}
// send array of todays unique invoice numbers (later all inv data?) to invdata sheet and log them
function logTodaysInvoices (invIDArr){
invIDArr.forEach
invDataRepo.getSheetByName('invdata').getRange(invDataRepo.getSheetByName('invdata').getLastRow()+1,1,invIDArr.length,1).setValue(invIDArr);
}
// return an array of unique invoice ids from todays invoice data
function uniqueInvIDs (){
let singleArray = invoiceData.map(row => row[5]);
let unique = [...new Set(singleArray)];
return unique;
}
//log incoicedata to invdatarepo-sheet 'lineitems'
function logLineItems (){
invDataRepo.getSheetByName('lineitems').getRange(invDataRepo.getSheetByName('lineitems').getLastRow()+1,2,invoiceData.length,invoiceData[0].length).setValues(invoiceData);
}
It's hard to say exactly what you need since we cannot see your Invoice Data Sheet.
But here's something that might give you a start:
let iobj = {idA:[]};
[35033817, 35033818, 35033819, 35033820, 35033821].forEach((id => {
if(!iobj.hasOwnProperty(id)) {
iobj[id]={date: invoiceDate, name: customName, items:[]};
iobj.idA.push(id);//I find it handy to have an array of object properties to loop through when I wish to reorganize the data after it's all collected
} else {
iobj[id].items.push({item info properties});//I am guessing here that you may wish to addition additional information about the items which are on the current invoice
}
});
Javascript Object
To follow up from your question:
Your loop to collect object data would start to look something like this:
function getInvoiceData() {
const ss = SpreadsheetApp.getActive();
const ish = ss.getSheetByName('Invoice Data');
const isr = 2;
const hA = ish.getRange(1, 1, 1, ish.getLastColumn()).getValues()[0];
let idx = {};//object return head index into row array based on header title which in this case I assume invoice number is labeled 'Invoicenumber'
hA.forEach((h, i) => {idx[h] = i});
const vs = ish.getRange(isr, 1, ish.getLastRow() - isr + 1, ish.getLastColumn()).getValues();
let iobj = { idA: [] };
vs.forEach(r => {
if (!iobj.hasOwnProperty(r[idx['invoicenumber']])) {
iobj[r[idx['invoicenumber']]] = { date: r[idx['invoicedate']], name: r[idx['customername']], items: [] };
iobj.idA.push(r[idx['invoicenumber']]);
} else {
iobj[r[idx['invoicenumber']]].items.push({ iteminfoproperties:'' });
}
});
}
I have an array with over 200 items from a .json file.
I want to know how I can return lets say the first 10 items or 20 items starting from the 7th index/item.
Example
OriginalArray = [{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}, {j}, {k}, {l}]
How do I get newArray = [{a}, {b}, {c}, {d}] or newArray = [{e}, {f}, {g}, {h}]
from the originalArray in typeScript or Javascript.
Thank you
Try this:
newArrayA = OriginalArray.slice(0, Math.round(OriginalArray.length/2)) // first half
newArrayB = OriginalArray.slice(Math.round(OriginalArray.length/2)) // second half
You need slice
const offset = 7;
console.log(
["{a}", "{b}", "{c}", "{d}", "{e}", "{f}", "{g}", "{h}", "{i}", "{j}", "{k}", "{l}"]
.slice(offset,offset+4)
)
In your case:
var newArray = OriginalArray.slice(7, 7+20);
In my Vue app I need to group an array by date and then sum multiple columns. I was able to group and sum 1 column this way:
receiptsByDate: function(){
let byDate = _.groupBy(this.receipts, 'date');
let totals = {};
_.forEach(byDate, function(amounts, Date){
totals[Date] = _.reduce( byDate[Date], function(sum, receipt){
return sum + parseFloat( receipt.total );
}, 0);
})
return totals;
}
which creates an object date: total.
This is a receipt sample on which the function is applied:
card_commission:null
created_at:"2019-11-14 06:13:20"
customer_id:null
date:"2019-11-14"
discount:"12000.0"
id:1
location_id:null
number:"2019-00001"
service:null
subtotal:"200000.0"
table_id:null
taxes:null
ticket_id:1
total:"188000.0"
updated_at:"2019-11-14 06:13:20"
I need instead to group by date but beside receipt.total I need to sum other columns like discount, subtotal and so on. I did not find anything online to achieve this. Anyone can point me in the right direction? It doesn't have to be with loadash another approach is ok too.
Instead of returning only total, you can return an object consist of all computed values for every date.
receiptsByDate: function(){
let byDate = _.groupBy(this.receipts, 'date');
let computedData = {};
_.forEach(byDate, function(receiptList, date){
computedData[date] = {
total: _.sumBy(receiptList, function(receipt) {
return parseFloat(receipt.total);
}),
discount: _.sumBy(receiptList, function(receipt) {
return parseFloat(receipt.discount);
})
}
};
return computedData;
}
Change reduce to another forEach. If you want to use Date as key, then
let sumary = {}
_.forEach(byDate[Date], (receipt) => {
if(sumary.total == null)
sumary.total = parseFloat(receipt.total)
else
sumary.total += parseFloat(receipt.total)
if(sumary.other== null)
sumary.other= parseFloat(receipt.other)
else
sumary.other+= parseFloat(receipt.other)
}
totals[Date] = summary
If this is what you want, then you could improve your code, just replace 0 with { total: 0, other: 0} and calculate inside the reduce function.
I am making my first project as a food rota that gives out a shopping list from the chosen Recipe ingredients.
I managed to write the loop that would combine all the ingredients in one array where it takes us to my question.
I would like to combine the same ingredients in the array ie: [1kg Carrots, 1kg Spinach, 1kg Carrots], I would like it to combine the repeating (1kg Carrots, 1kg Carrots) into (2kg Carrots)
Is there a way to do this?
Sorry if my request is sloppy, first time asking a question.
I could work it so that it would cancel out the similar ones as the outcome of [1kg Carrots, 1kg Carrots] would be [1kg Carrot].
Unfortunately I am at work at the moment and do not have access - will update if needed.
I would most likely create an object from the array.
const arr = ['1kg Carrots', '1kg Spinach', '1kg Carrots'];
let obj = {};
arr.forEach(element => {
let [kg, item] = element.split(' ');
kgNum = parseInt(kg);
if(Object.keys(obj).includes(item)){
return obj[item] += kgNum;
} else {
obj[item] = kgNum;
}
})
obj
// #=> { Carrots: 2, Spinach: 1 }
I loop over the array
I split the element (eg. '1kg Carrots') into the weight and item
then I coerce the 1kg into an integer
I check if the obj already has a key of item and if it doesn't I add it
If it does already exist I just increment kgNum
and then I return the object
This is a good place to start and you can figure out with a little more work of how to add back the kg :)
it can be done in 2 steps
var arr = ["1kg Carrots", "1kg Spinach", "1kg Carrots"]
step 1: count total number of kg
var arrCount = arr.reduce((ac, val)=> {
var [kg, key] = val.split(' ')
kg = parseFloat(kg)
ac[key] = ac[key]? ac[key]+kg : kg;
return ac
}, {}) // { Carrots: 2, Spinach: 1 }
step 2: revert it to array
var out = Object.entries(arrCount).map(([key, kg])=> `${kg}kg ${key}`)
// [2kg Carrots, 1kg Carrots]
I am currently working a project that I have to use js and php to retrieve data from the gateway. Now that i have retrieved it, but the data is not organised:
{"timestamp":1526524809413,"data":[
{"_id":"rJeixnNtpG","data":"N11B00074","raw":
[78,49,49,66,48,48,48,55,52],"timestamp":1525398515116},
{"_id":"HkzognEYpf","data":"N11E00000","raw":
[78,49,49,69,48,48,48,48,48],"timestamp":1525398515479},
{"_id":"BJxXp4t6M","data":"N11A00029","raw":
[78,49,49,65,48,48,48,50,57],"timestamp":1525398807747}
As you can see there are three types of data: the one starts with B(N11B00074), E(N11E00000) and A(N11A00029), followed by the 5 digits which is the data i wanted to split from the string while categorised by the type(B, E and A).
I have three tables in my web page and want to put the data into them based on the types: Like B being humidity table, A being temperature table and E being pH readings table.
So far i only managed to list them out in a table.
Is there a way that I can seperate the string and put them into an array based on their types?
You can use reduce to group objects in an array:
const input={"timestamp":1526524809413,"data":[{"_id":"rJeixnNtpG","data":"N11B00074","raw":[78,49,49,66,48,48,48,55,52],"timestamp":1525398515116},{"_id":"HkzognEYpf","data":"N11E00000","raw":[78,49,49,69,48,48,48,48,48],"timestamp":1525398515479},{"_id":"BJxXp4t6M","data":"N11A00029","raw":[78,49,49,65,48,48,48,50,57],"timestamp":1525398807747}]}
const arranged = input.data.reduce((accum, obj) => {
const { data } = obj;
const type = data[3];
const digits = data.slice(5);
if (!accum[type]) accum[type] = [];
accum[type].push({ ...obj, digits });
return accum;
}, {});
console.log(arranged);
// If you want an array and not an object:
console.log(Object.values(arranged));
If you want to group the array into an object. You can use reduce. You can get the fourth character of the string by using charAt
let arr = {"timestamp":1526524809413,"data":[{"_id":"rJeixnNtpG","data":"N11B00074","raw": [78,49,49,66,48,48,48,55,52],"timestamp":1525398515116}, {"_id":"HkzognEYpf","data":"N11E00000","raw": [78,49,49,69,48,48,48,48,48],"timestamp":1525398515479}, {"_id":"BJxXp4t6M","data":"N11A00029","raw":[78,49,49,65,48,48,48,50,57],"timestamp":1525398807747}]};
let result = arr.data.reduce((c, v) => {
let l = v.data.charAt(3); //Get the 4th chatacter
c[l] = c[l] || [];
c[l].push(v);
return c;
}, {});
console.log( result );