I have a string containing many lines of the following format:
<word1><101>
<word2><102>
<word3><103>
I know how to load each line into an array cell using this:
var arrayOfStuff = stringOfStuff.split("\n");
But the above makes one array cell per line, I need a two-dimensional array.
Is there a way to do that using similar logic to the above without having to re-read and re-process the array. I know how to do it in two phases, but would rather do it all in one step.
Thanks in advance,
Cliff
It sounds like you're hoping for something like Python's list comprehension (e.g. [line.split(" ") for line in lines.split("\n")]), but Javascript has no such feature. The very simplest way to get the same result in Javascript is to use a loop:
var lines = lines.split("\n");
for (var i = 0; i < lines.length; i++) {
lines[i] = lines[i].split(" ");
// or alternatively, something more complex using regexes:
var match = /<([^>]+)><([^>]+)>/.exec(lines[i]);
lines[i] = [match[1], match[2]];
}
Not really. There are no native javascript functions that return a two-dimensional array.
If you wanted to parse a CSV for example, you can do
var parsedStuff = [];
stringOfStuff.replace(/\r\n/g, '\n') // Normalize newlines
// Parse lines and dump them in parsedStuff.
.replace(/.*/g, function (_) { parsedStuff.push(_ ? _.split(/,/g)) : []; })
Running
stringOfStuff = 'foo,bar\n\nbaz,boo,boo'
var parsedStuff = [];
stringOfStuff.replace(/\r\n/g, '\n')
.replace(/.*/g, function (_) { parsedStuff.push(_ ? _.split(/,/g)) : []; })
JSON.stringify(parsedStuff);
outputs
[["foo","bar"],[],["baz","boo","boo"]]
You can adjust the /,/ to suite whatever record separator you use.
Related
I have an Array of Arrays populated from C# Model:
var AllObjectsArray = [];
#foreach(var Cobject in Model.ObjectList)
{
#:AllObjectsArray.push(new Array("#Cobject.Name", "#Cobject.Value", "#Cobject.Keyword"));
}
var SelectedObjects = [];
uniqueobj.forEach(function (element) {
SelectedObjects.push(new Array(AllObjectsArray.filter(elem => elem[0] === element))); //makes array of selected objects with their values(name,value,keyword)
});
I am trying to get second parameter of each and every inner Array and add it to new array containing those elements like this:
var ValuesArray = [];
for (i = 0; i < SelectedObjects.length; i++) {
ValuesArray.push(SelectedObjects[i][0]) //problem here i think
};
Unfortunately, on:
alert(ValuesArray + " : " + SelectedObjects);
I get nothing for ValuesArray. The other data for SelectedObjects loads properly with all three parameters correctly returned for each and every inner Array,so it is not empty. I must be iterating wrongly.
EDIT:
SOme more info as I am not getting understood what I need.
Lets say SelectedObjects[] contains two records like this:
{ name1, number1, keyword1}
{ name2, number2, keyword2}
Now, what I need is to populate ValuesArray with nane1 and name2.
That is why I was guessing I should iterate over SelectedObjects and get SelectedObject[i][0] where in my guessing i stands for inner array index and 1 stands for number part of that inner array. Please correct me and put me in the right direction as I am guesing from C# way of coding how to wrap my head around js.
However SelectedObject[i][0] gives me all SelectedObject with all three properties(name, value and keyword) and I should get only name's part of the inner Array.
What is happening here?
Hope I explained myself better this time.
EDIT:
I think I know why it happens, since SelectedObjects[i][0] returns whole inner Array and SelectedObjects[i][1] gives null, it must mean that SelectedObjects is not Array of Arrays but Array of strings concatenated with commas.
Is there a way to workaround this? SHould I create array of arrays ddifferently or maybe split inner object on commas and iteratee through returned strings?
First things first, SelectedObjects[i][1] should rather be SelectedObjects[i][0].
But as far as I understand you want something like
var ValuesArray = [];
for (let i = 0; i < SelectedObjects.length; i++) {
for(let j = 0; j <SelectedObjects[i].length; j++) {
ValuesArray.push(SelectedObjects[i][j]);
}
};
In this snippet
var ValuesArray = [];
for (i = 0; i < SelectedObjects.length; i++) {
ValuesArray.push(SelectedObjects[i][1]) //problem here i think
};
You're pointing directly at the second item in SelectedObjects[i]
Maybe you want the first index, 0
I have a fairly large javascript/html application that updates frequently and receives a lot of data. It's running very quickly and smoothly but I need to now introduce a function that will have to process any incoming data for special chars, and I fear it will be a lot of extra processing time (and jsperf is kinda dead at the moment).
I will make a request to get a .json file via AJAX and then simply use the data as is. But now I will need to look out for strings with #2C (hex comma) because all of the incoming data is comma-separated values.
in File.json
{
names: "Bob, Billy",
likes : "meat,potatoes
}
Now I need
{
names: "Bob, Billy",
likes : "meat#2Cbeear#2Cwine,potatoes
}
where #2C (hex for comma) is a comma within the string.
I have this code which works fine
var str = "a,b,c#2Cd";
var arr = str.split(',');
function escapeCommas(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].indexOf("#2C") !== -1) {
var s = arr[i].replace("#2C", ',');
arr[i] = s;
}
}
return arr;
}
console.log(escapeCommas(arr));
http://jsfiddle.net/5hogf5me/1/
I have a lot of functions that process the JSON data often as
var name = str.split(',')[i];
I am wondering how I could extend or re-write .split to automatically replace #2C with a comma.
Thanks for any advice.
Edit: I think this is better:
var j = {
names: "Bob, Billy",
likes : "meat#2Cpotatoes"
};
var result = j.likes.replace(/#2C/g, ',');
// j.likes.replace(/#2C/ig, ','); - if you want case insensitive
// and simply reverse parameters if you want
console.log(result);
This was my initial approach:
var j = {
names: "Bob, Billy",
likes : "meat,potatoes"
}
var result = j.likes.split(",").join("#2C")
console.log(result);
// meat#2Cpotatoes
Or if you have it the reverse:
var j = {
names: "Bob, Billy",
likes : "meat#2Cpotatoes"
}
var result = j.likes.split("#2C").join(",")
console.log(result);
// meat,potatoes
[Updated to reflect feedback] - try at http://jsfiddle.net
var str = 'a,b,c#2Cd,e#2Cf#2Cg';
alert(str.split(',').join('|')); // Original
String.prototype.native_split = String.prototype.split;
String.prototype.split = function (separator, limit) {
if ((separator===',')&&(!limit)) return this.replace(/,/g,'\0').replace(/#2C/gi,',').native_split('\0');
return this.native_split(separator, limit);
}
alert(str.split(',').join('|')); // Enhanced to un-escape "#2C" and "#2c"
String.prototype.split = String.prototype.native_split;
alert(str.split(',').join('|')); // Original restored
Couple minor tangential notes about your function "escapeCommas": this function is really doing a logical "un-escape" and so the function name might be reconsidered. Also, unless it is your intention to only replace the first occurence of "#2C" in each item then you should use the "g" (global) flag, otherwise an item "c#2Cd#2Cde" would come out "c,d#2Ce".
I'm trying to merge multiple arrays evenly/alternating in javascript/Google appScript. There are several arrays (5 or 6). I've tried 2 different methods, but neither worked. I don't work a lot with javascript honestly and I've managed to get the code to this point, but I can't get it merge properly; and most of them said merging two arrays to one (might be my problem).
I've seen plenty on php examples that were on how to do this and they are pretty straight forward in logic reading and I understand them better, but all javascript methods I've looked at and tried so far have failed to produce the results I want. I'm not sure if it's the way AppScript is formatting the arrays or they're just no made to handle more that 2.
My data looks similar to this at the moment:
var title = ["sometitle1","sometitle2","sometitle3"];
var link = ["somelink1","somelink2","somelink3"];
var date = ["somedate1","somedate2","somedate3"];
var data = ["somedata1","somedata2","somedata3"];
var all = [title,link,date,data];
var mix = [];
Note: all the variable data will/should be the same length since the data is being pulled from a spreadsheet.
My desired output is:
mix = ["sometitle1","somelink1","somedate1","somedata1","sometitle2","somelink2","somedate2","somedata2","sometitle3","somelink3","somedate3","somedata3"];
I tried using appscript to merge them with this: return ContentService.createTextOutput(title + link + data + date), but it didn't work out properly, it printed them in that order instead of merging the way I'd like them too.
Then I tried using a loop merge that I found here on sstackoverflow:
for (var i = 0; all.length !== 0; i++) {
var j = 0;
while (j < all.length) {
if (i >= all[j].length) {
all.splice(j, 1);
} else {
mix.push(all[j][i]);
j += 1;
}
}
}
But it splice merges every letter with a comma
mix = [s,o,m,e,t,i,t,l,e,1,s,o,m,e,t,i,t,l,e,2,s,o,m,e,t,i,t,l,e,3,s,o,m,e,l,i,n,k,1,...]
and doesn't alternate data either.
The code (2 version) I'm working on is: here with Output
&
Here with Output
(Also, dumb question, but do I use title[i] + \n OR title[i] + "\n" for adding new lines?)
Use a for loop and the push() method like this :
function test(){
var title = ["sometitle1","sometitle2","sometitle3"];
var link = ["somelink1","somelink2","somelink3"];
var date = ["somedate1","somedate2","somedate3"];
var data = ["somedata1","somedata2","somedata3"];
//var all = [title,link,date,data];
var mix = [];
for(var n=0;n<title.length;n++){
mix.push(title[n],link[n],date[n],data[n]);
}
Logger.log(JSON.stringify(mix));
}
And also : title[i] + "\n" for adding new lines
Edit following comments :
Your code should end like this :
...
for(var n=0;n<titles.length;n++){
mix.push(titles[n],links[n],descriptions[n],pubdates[n],authors[n]);
}
var mixString = mix.join('');// convert the array to a string without separator or choose the separator you want by changing the argument.
//Print data and set mimetype
return ContentService.createTextOutput(mixString)
.setMimeType(ContentService.MimeType.RSS);
}
I have two versions of a horizontal bar chart, stacked and paired (aka grouped). The code for each is stuffed into their own functions.
Refer to lines 35-43 (var stacked = function (){ ... }) and lines 117-121 (var paired = function (){ ... }) to see how the CSV is currently being parsed: http://tributary.io/inlet/8832116
Uncomment line 197 and below to see the stacked version rendered. To do this I manually changed the data, not ideal.
GOAL: I want to parse the csv file and drop a column programmatically, rather than remove it manually and save 2 separate csv files.
I need to parse the csv and remove this with native d3 or javascript code, but how?
Shown in code.
I have:
Category,Total,Under $1000, ...
Music,14744,1434, ...
Art,12796,1216, ...
I need total removed:
Category,Under $1000, ...
Music,1434, ...
Art,1216, ...
If you have the CSV string in memory (a variable string), split on \n to get the lines, loop over each line and split on ,. This will give you an array of the column values for a given line.
Splice out the column you don't want, and then join line back with , - this will get you back a line of CSV data that you can push onto a result array.
Finally at the end, join the result array with \n and there you have it - a new string containing CSV data without column you don't want.
Note that this will not properly handle quotes / other gotcha's that come with CSV data, but if your data doesn't contain any of that you're in the clear.
Sample using map:
// raw CSV data from somewhere
var csv =
'Category,Total,Under $1000\n' +
'Music,14744,1434,3450\n' +
'Art,12796,1216,7748\n';
// split on newlines, map over each line
var newCsv = csv.split('\n').map(function(line) {
var columns = line.split(','); // get the columns
columns.splice(1, 1); // remove total column
return columns;
}).join('\n'); // join on newlines
console.log(newCsv);
http://jsfiddle.net/PZ9vM/
Add the column removal as suggested by Trevor to this and your csv parser can handle stuff like quotes as well.
Maybe just use some splicing and slicing?
var data; //note, you're loading it in as a flat file with $.get()
$.get("/url/to/the/csvfile", function(d){
data = d.splice("\n");
var length = data.length; //so as to save loop runtime
for (var i = 0; i < length; i ++){
data[i] = data[i].splice(",")[0] + data[i].splice(",").slice(2)
//this will split data[i] into the first piece before the comma
//along with everything from the 2nd index to the end of the
//array that was spliced with ","
}
}
splicing and slicing are so much fun...
edit:
I forgot that you don't need to specify the end index with .slice().
Here's a nifty little vanilla JavaScript for you to remove a column from CSV data:
Working Demo
Code:
var csv =
'Category,Total,Under $1000\n' +
'Music,14744,1434,3450\n' +
'Art,12796,1216,7748\n';
// Made it a function to make it reusable!
function removeColumn(data, colIndex) {
var temp = data.split("\n");
for(var i = 0; i < temp.length; ++i) {
temp[i] = temp[i].split(",");
temp[i].splice(colIndex,1);
temp[i] = temp[i].join(","); // comment this if you want a 2D array
}
return temp.join("\n"); // returns CSV
return temp; // returns 2D array
return d3.csv.parse(temp); // returns a parsed object
}
console.log(removeColumn(csv,1));
Why can't I output my regex to a variable, and then run regex on it a second time?
I'm writing a greasemonkey javascript that grabs some raw data, runs some regex on it, then runs some more regex on it to refine the results:
// I tried this on :: http://stackoverflow.com/
var tagsraw = (document.getElementById("subheader").innerHTML);
alert(tagsraw);
Getting the raw data (above code) works
var trimone = tagsraw.match(/title\W\W\w+\s\w+\s\w+\s\w+\s\w+/g);
alert(trimone);
running regex once works (above code); but running (code below) doesn't??
var trimtwo = trimone.match(/\s\w+\s\w+\s\w+\s\w+/g);
alert(trimtwo);
Can some advise me as to what is wrong with my code/approach?
The reason the first match works, is because innerHTML returns a string.
However the match returns an array, thus treat it as one:
for (var i=0; i<trimone.length; i++)
{
var trimtwo = trimone[i].match(/\s\w+\s\w+\s\w+\s\w+/g);
alert(trimtwo);
}
Edit:
Try this code instead though, I think this is a bit closer to what you want to achieve:
var trimone = tagsraw.match(/title\s*=\s*".*"/g);
alert(trimone);
for (var i=0; i<trimone.length; i++)
{
alert(trimone[i]);
}
You could do something like this:
var str = "<title> foo bar baz quux blah</title>",
re = [
/title\W\W\w+\s\w+\s\w+\s\w+\s\w+/g,
/\s\w+\s\w+\s\w+\s\w+/g
],
tmp = [str];
for (var i=0, n=re.length; i<n; ++i) {
tmp = tmp.map(function(val) {
return val.match(re[i])[0];
});
}
alert(tmp);
.match should be returning an array, not a string.
Your case is better suited to using .exec. You could even chain the two if you don't care about the intermediate result:
/\s\w+\s\w+\s\w+\s\w+/g.exec(/title\W\W\w+\s\w+\s\w+\s\w+\s\w+/g.exec(tagsraw));
The problem is that match() returns an array and there is no built-in function to perform a regular expression on an array.
So instead you should be able to do this with the exec function from the Regexp object. It will return the matched string. You can grab the matched string from the first regexp and use it for the second.
So it'd be something like this:
var patt1 = new Regexp(/title\W\W\w+\s\w+\s\w+\s\w+\s\w+/g);
var trimone = patt1.exec(tagsraw);
if (trimone != null) // might be null if no match is found
{
alert(trimone);
var patt2 = new Regexp(/\s\w+\s\w+\s\w+\s\w+/g);
var trimtwo = patt2.exec(trimone);
alert(trimtwo);
}
Note that exec returns null if no match is found so be sure to handle that in your code like I do above.