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 );
Related
I have a list of hrefs with product data:name and it's id. First of all i removed prod Id that i'll use as separate variable.
After this, the remained part of href should be used as the product name.
var prodHref = document.querySelectorAll('.widget-products-list-item-label');
var allHref = [];
for(var i=0;i<prodHref.length;i++){
allHref.push(prodHref[i].href.split('/')[5])
}
var prodName = [];
for(var i=0;i<allHref .length;i++){
prodName.push(allHref [i].slice(0, -1))
}
var prodNameNew=[];
for(var i=0;i<prodName .length;i++){
prodNameNew.push(prodName[i].slice(0, -1))
}
So, the final result is on the attached screen. N
How i have concatenate all the elements of each array in order to get new arrays in the following format: Nokia G20 4 64 Albastru, Motorola G60 gri etc
Thank You
You want to capitalize the items of the inner arrays and then join them by space.
One way to do it is:
let result = arr.map(a => a.map(capitalize))
.map(a => a.join(" "))
where capitalize should be a function that takes a string and returns a string with first letter in upper case if possible.
You can find this in answers for the more specific SO question:
How do I make the first letter of a string uppercase in JavaScript?
Instead of 3 separate loops, we can get the substring based on single iteration only using Array.map() along with String.slice().
const prodHref = [{
href: "https://abc/def/ghi/alpha/mno"
}, {
href: "https://abc1/def1/ghi1/beta/mno1"
}, {
href: "https://abc2/def2/ghi2/gamma/mno2"
}, {
href: "https://abc3/def3/ghi3/omicron/mno3"
}];
const allHref = prodHref.map((obj) => obj.href.split('/')[5].slice(0, -2));
console.log(allHref);
Now you can use Array.join() method to join the result array.
const allHref = ["alp", "be", "gam", "omicr"];
console.log(allHref.join(" "));
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 need to convert data from a csv file into a JavaScript object where key for each object is the id from the data. One JS object per each user.
Question: Is there a way to solve it using vanilla JS?
I need at the least a general walkthrough of what to do cause all I've been able to find is methods on how to solve this by using jQuery or JSON but for the research I am trying to understand, I can't use a specialized library, I'm only allowed to use plain VanillaJS.
Sample text data:
id first_name last_name email gender
-- ---------- --------- ----- ------
1 Gloria Mendez gmendez#ipu.gov Female
2 Lucy Grey lgrey#gmail.com Female
3 Max Mcolom mmcolom#yahoo.com Male
4 David Cooke dcooke#gmail.com Male
5 Marwin Darge mdarge#gov.com Male
hundreds of other rows
Desired output:
{
1: {
id: 1, first_name: 'Gloria', last_name: 'Mendez', email: 'gmendez#ipu.gov', gender: 'female'
},
2: {
id: 1, first_name: 'Lucy', last_name: 'Grey', email: 'lgrey#gmail.com', gender: 'female'
},
...
}
Using vanilla JS below.
I've added comments to explain what the code is doing. It;s basically splitting the data into rows, and then cells, and doing array manipulation along the way:
let table =
`id first_name last_name email gender
-- ---------- --------- ----- ------
1 Gloria Mendez gmendez#ipu.gov Female
2 Lucy Grey lgrey#gmail.com Female
3 Max Mcolom mmcolom#yahoo.com Male
4 David Cooke dcooke#gmail.com Male
5 Marwin Darge mdarge#gov.com Male`
// Split into rows, and then split each row into cells
let rows = table.split(/[\r\n]+/g).map(row => row.trim().split(/[\s\t]+/g));
// The first row will be the header
let header = rows[0];
// The rest is the data
let data = rows.slice(2);
// Create a function to return the desired object structure
function formatObject(headers, cells) {
return headers.reduce((result, header, idx) => {
result[header] = cells[idx];
return result;
}, {});
}
// Reduce each row into the desired format, and use the ID as a key
let result = data.reduce((res, row, idx) => {
let value = formatObject(header, row);
res[value.id] = value;
return res;
}, {});
// Log the result
console.log(result);
Parse the file
split on line break \n, to get rows
const rows = csv.split('\n');
split each row on comma , to get cells (if it's CSV, otherwise, \t for TSV)
const rawData = rows.map(d => d.split(',');
Extract the headers from the 1st row
The first row of data is you list of keys to build objects
const headers = rawData[0]
Convert rows into objects
const data = rawData.slice(2); // get rid of first 2 rows
const output = data.map(row => {
const obj = {};
headers.forEach((h, i) => obj[h] = row[i] });
return obj;
});
Of course, you need to handle all sorts of edge cases, like commas in the CSV cell, missing data etc...
I hope this gets you started.
Assuming you are loading the data already, you could loop through the data and use javascripts object bracket notation to define the new properties based on the id.
If you are looking for step by step,
first load the csv using something like node's fs module or the filereader in the browser.
for each line read parse the csv with javascript split.
if the assuming the id is always the first column you can now get
the id of the data with the splitArray[0].
Create a new object, then use bracket notation to set the property
of the object to the id. ex.
var obj = {};
obj[splitArray[0]] = data;
This is really rough, untested, but should get you closer to where you need to go.
Assuming a double quoted comma separated file which is about the most common csv format:
/* empty lines shown on purpose to approximate real file */
const csvString =
`"id","first_name","last_name","email","gender"
"1","Gloria","Mendez","gmendez#ipu.gov","Female"
"2","Lucy","Grey","lgrey#gmail.com","Female"
"3","Max","Mcolom","mmcolom#yahoo.com","Male"
"4","David","Cooke","dcooke#gmail.com","Male"
"5","Marwin","Darge","mdarge#gov.com","Male"`;
//split string on line breaks into array of line strings
const csvLines=csvString.split('\n');
// filter empty lines out and map each line to sub array
let arr = csvLines.filter(s=>s.trim()).map(arrFromLine)
// get headings from first line
let headings = arr.shift();
// map all the other lines into objects
let res = arr.map(lineArr =>{
return lineArr.reduce((a,c, i)=>{
a[headings[i]] = c;
return a
},{})
});
// map lines to array helper function
function arrFromLine(str){
// remove quotes on each end, split at `","` to avoid any other commas in text
return str.trim().slice(1, str.length-1).split('","');
}
console.log(res)
.as-console-wrapper { max-height: 100%!important;}
I would like to store product information in a key, value array, with the key being the unique product url. Then I would also like to store the visit frequency of each of these products. I will store these objects as window.localStorage items, but that's not very important.
The thing I had in mind was two key value arrays:
//product information
prods["url"] = ["name:product_x,type:category_x,price:50"]
//product visits frequency
freq["url"] = [6]
Then I would like to sort these prods based on the frequency.
Is that possible?
Hope you guys can help! Thanks a lot
Well you seem to have made several strange choices for your data format/structure. But assuming the format of the "prod" is beyond your control but you can choose your data structure, here's one way to do it.
Rather than two objects both using url as a key and having one value field each I've made a single object still keyed on url but with the product and frequency information from each in a field.
Objects don't have any inherent order so rather than sorting the table object I sort the keys, your "url"s ordered by ascending frequency.
To show that it's sorted that way I print it out (not in the same format).
For descending frequency, change data[a].freq - data[b].freq to data[b].freq - data[a].freq
var data = {
"url": {
prod: "name:product_x,type:category_x,price:50",
freq: 6
},
"url2": {
prod: "name:product_y,type:category_y,price:25",
freq: 3
}
};
var sorted = Object.keys(data).sort((a, b) => data[a].freq - data[b].freq);
console.log(sorted.map(k => [data[k].freq, k, data[k].prod]));
There's more than one way to format the data, which would change the shape of the code here.
maybe something like this:
var prods = [
{url:1, val:[{name:'a',type:'x',price:60}]},
{url:2, val:[{name:'b',type:'x',price:30}]},
{url:3, val:[{name:'c',type:'x',price:50}]},
{url:4, val:[{name:'c',type:'x',price:20}]},
{url:5, val:[{name:'c',type:'x',price:10}]},
{url:6, val:[{name:'c',type:'x',price:40}]}
];
var freq = [
{url:1, freq:6},
{url:2, freq:3},
{url:3, freq:5},
{url:4, freq:2},
{url:5, freq:1},
{url:6, freq:4}
];
prods.sort(function (a, b) {
var aU = freq.filter(function(obj) {
return obj.url === a.url;
});
var bU = freq.filter(function(obj) {
return obj.url === b.url;
});
if (aU[0].freq > bU[0].freq) {
return 1;
}
if (aU[0].freq < bU[0].freq) {
return -1;
}
return 0;
});
My data is in the following format..
var data= [['typeName', 'valueName'], ['type1', 'value1'],
['type1', 'value2'],['type2', 'value3'],['type2', 'value4']]
I wish to transform the above data to data as below..
var resultdata=[{'typeName':'type1','valueName':['value1','value2']},
{'typeName':'type2','valueName':['value3','value4']}]
Basically I pick up distinct 'typeName' values and then group 'valueName' values by 'typeName' values.
I would preferably use only knockoutjs, lodash or underscorejs as my soln already uses them but I'm open to other solutions as well..
All help is sincerely appreciated
Thanks
I think this solution using underscore should do the trick:
var result= _.chain(data)
.rest()
.groupBy( value => value[0])
.map( (value,key) => ({ [data[0][0]]: key, [data[0][1]]: _.map(value, val => val[1])}))
.value();
This solution uses rest to skip the first item in the data array (the type descriptors). The array is then grouped by the first value in the array (the type) and the mapping returns the grouping in the required form using es6 object initializer notation.
Given the result as:
var resultdata=[
{'typeName':'type1'},{'valueName':['value1','value2']},
{'typeName':'type2'},{'valueName':['value3','value4']}
]
I'm going to call 'typeName' the category and 'valueName' the items.
Since the original data look like this:
var data= [
['typeName', 'valueName'],
['type1', 'value1'],
['type1', 'value2'],
['type2', 'value3'],
['type2', 'value4']
]
It is clear there is a pattern. The first row of data is what we'll use as labels for category and items. All the remaining data represent the values being used inside category and items.
The first step is to extract the labels:
var categoryLabel = data[0][0];
var itemLabel = data[0][1];
Next, the unique categories will need to be determined, so we'll use reduce to build an array of unique categories:
var categories = data
.filter(function(row, i) { return i > 0 }) // remove the labels
.reduce(function(arrCategories, currRow) {
// Add the current rows' category if it doesn't already exist
var currCategory = currRow[0];
if (arrCategories.indexOf(currCategory) === -1) {
return arrCategories.concat(currCategory);
}
return arrCategories;
}, [])
Now that you have a set of categories, you just need to iterate over each one to find all items that belong to it:
var valuesByCategory = {};
categories.forEach(function(category) {
// find all the data items that match the category
var items = data
.filter(function(row) { return row[0] === category; })
.reduce(function(arrItems, currRow) {
var currItem = currRow[1];
if (arrItems.indexOf(currItem) === -1) {
return arrItems.concat(currItem);
}
return arrItems;
}, []);
valuesByCategory[category] = items;
});
Now that all the data has been parsed out, the only thing left to do is build the resultant array:
var resultdata = [];
// iterate through each of the categories
categories.forEach(function(category) {
// using the category label, output an object with the label and category
var categoryObj = {};
categoryObj[categoryLabel] = category;
resultdata.push(categoryObj);
// Next, create a items object containing all the values
var itemsObj = {};
itemsObj[itemLabel] = valuesByCategory[category];
resultdata.push(itemsObj);
}
and that's it :)
The best part is that you don't need any external libraries. This is all ES2015 javascript!
Here is a lodash version of Gruff Bunnies solution:
var data= [['typeName', 'valueName'], ['type1', 'value1'], ['type1', 'value2'],['type2', 'value3'],['type2', 'value4']]
var names = data[0]
var values = _.tail(data)
console.log(JSON.stringify(
_(values)
.groupBy(0)
.map( (value, key) => ({ [names[0]]: key, [names[1]]: _.map(value, 1)}) )
.value()
))
https://jsfiddle.net/nmf1fdf5/