Javascript regex string number pairs variable length - javascript

I'm trying to parse a data set in javascript using regex to pick out certain sections. One particular section consists of an unknown number of string-number pairs (i.e. the number of pairs is unknown in advance--can be 1 to x) starting with a known string (e.g. "Amount") and ending with a known string (e.g. "End"). For example, here's one data set with 3 such pairs:
Donation
Amount
Red Cross
1,630.83
Humanity First
500.00
Global Health
100.00
End
I ran the dataset through the following commands to get rid of whitespaces:
body = body.replace(/\n/g,"");
body = body.replace(/\r/g,"");
This results in the following string:
DonationAmountRed Cross1,630.83Humanity First500.00Global Health100.00End
If the number entries is fixed and known, say 1 entry, I know the regex for parsing it:
const REGEX_DONATION_AND_AMOUNT = new RegExp("DonationAmount([a-zA-Z\\s]+)(\\d+\.\\d+)End");
receiptData.donation = body.match(REGEX_DONATION_AND_AMOUNT)[1];
receiptData.amount = body.match(REGEX_DONATION_AND_AMOUNT)[2];
But when the number of entries is variable, how can I loop through and parse this to get an array of donation type and amount pairs? Thank you for any help you can provide!

Do this in two steps.
First get everything between Amount and End.
Then use a second regexp to get each item and amount.
let body = `Donation
Amount
Red Cross
1,630.83
Humanity First
500.00
Global Health
100.00
End`;
let donationString = body.match(/Donation\nAmount\n(.*)End/s)[1];
let donationItems = [...donationString.matchAll(/(.*)\n(.*)\n/g)];
console.log(donationItems);

This javascript procedure .splits the input data into an array where each element is a line field of your starting list.
A regular loop iterates the array looking for 'Amount', if found the values in the elements following it are added to a results array in pairs. When a pair is added, the next element is checked for 'End'. If there is no 'End', the next pair of lines are added to the results array until 'End' is encountered (and the loop reenters on the next element to repeat the process). Any data between 'End' and the next 'Amount' is ignored.
(I've expanded your input with some repetition to show the effect of more than one block with different numbers of pairs in each)
const linesArray = `Donation
Amount
Red Cross
1,630.83
Humanity First
500.00
Global Health
100.00
End
Donation
Amount
Red Cross
1,630.83
Global Health
100.00
End`.split('\n');
dataPairs = [];
for (let i=0; i<linesArray.length; i++) {
if (linesArray[i]=='Amount') {
while (linesArray[i+1] != 'End') {
dataPairs.push([linesArray[++i], linesArray[++i]]);
} // wend;
} // end if Amount;
if (linesArray[i] == 'End') continue;
} // next i;
console.log(dataPairs);
As presented, data pairs are not segregated for different blocks and each pair is in its own two-element array. The code could be modified to add each pair as a two-property object is required. The loop structure would remain the same.

Related

Set value to an array in pentaho javascript step

i have some values in the input and i want to save them into an array but first i want to set the "0" index of the array to 0 and then in the 1,2,3,4 indexs add the value of the input but i can get to make it
before to set the values of the input i set the 0 to the position 0 of the array but it doesnt work
the thing is that i want to use only the first four number of the input_data into an array but first set the 0 position to 0 and then add 5,10,15,20.
so the final array would be 0,5,10,15,20
i set the index "0" of the array to 0 and the other indexes i fill them whit the incoming data.
This depends on how the data is reaching the 'Modified Java Script Value' step.
If it is one single row, with the string containing a "CSV", then Rohit.007 answer will suffice.
If you have multiple rows reaching the step, the Script will Repeat N(row) times. If you have 4 rows being fed to the step, this script will run 4 times, so you need some sort of restraint on the Variables, so you don't repeat some parts of the code.
Personally i would use something like this for Pentaho:
I generated 4 rows, with an add sequence , 1 to 4.
The first run of the script creates the array, pushes 0 and the value of the first row. The other iterations of the script just keep pushing whatever values are found on the specified row to this array (without "Re-declaring" it).
Remenber that the "For Each" command is kind of blurred in pentaho, since you're almost always dealing with multi-row tables, so whatever you do in scripts has to have some constraints on variables declarations.
You can try the below code.
let array = [];
array.push(0);
let string = '1,2,3,4';
array = array.concat(string.split(','));
let result = array.map(function (x) {
return parseInt(x, 10);
});
console.log(result);

Do undefined elements in an array have an impact in JS? [duplicate]

This question already has answers here:
Deleting array elements in JavaScript - delete vs splice
(29 answers)
Closed 4 years ago.
I couldn't find a question that specifically targets the issue I'm having hence this question is being asked.
I have an array that holds 5 numbers:
var numbers = [0,1,2,3,4];
Once a number is clicked on the frontend (website), the number is removed from the array using the below code:
delete numbers[1];
This removes the correct number but leaves a space where the number was (the space is undefined). I believe this is causing an issue. After a number is removed from the array, I use another function to randomly pick any of the remaining numbers in the array however it sometimes fails. After much thought, I've realized it may be because there are empty spaces in the array after a number is removed and as a result, the code fails to work due to the undefined element.
Is my analogy correct or am I mistaken?
(I have also attempted to use the splice method to remove the number however that then causes an issue with the length of my array because if I later want to remove another number, it removes the wrong one due to the numbers moving around etc).
What you'd want to use is splice
In your specific case, numbers.splice(1,1)
You're correct that delete replaces one of the values in the array with undefined, and does not change the array length. Later on when you randomly choose an element from the array, you can wind up getting that undefined value, because it's still taking up a slot in the array:
var numbers = [0,1,2,3,4];
delete numbers[3];
console.log(numbers)
Instead use splice, which removes the item from the array completely:
var numbers = [0,1,2,3,4];
numbers.splice(3,1) /// remove one element starting at index 3
console.log(numbers)
if I later want to remove another number, it removes the wrong one due to the numbers moving around
You do need to choose one behavior or the other. If you need to preserve indexes as is, then continue to use delete, leaving the undefined values in the array, and rewrite your "choose one at random" function to never pick undefined values:
// start with some undefined values:
var numbers = [0, 1, undefined, undefined, undefined, 5]
var pickRandom = function(numbers) {
// make a copy of the array, removing undefined elements:
var definedValues = numbers.filter(function(item) {
return item !== undefined;
});
if (definedValues.length === 0) {return false}
//choose one at random:
return definedValues[Math.floor(Math.random() * definedValues.length)]
}
// test it:
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
(...but note that this suggests that a simple array is the wrong data structure to use here; you may be better off with an array of objects each with an explicit ID, so you can reference specific ones as needed without worrying about keeping the array index the same.)
If you mean to actually remove the element from the array, leaving your array with 4 elements, then you can use
numbers.splice(1);
This will remove the element in the index 1 from the array and return the section of the new array.

Looping over undefined array keys

Problem:
I have a DB containing math exercises, split by difficulty levels and date taken.
i want to generate a diagram of the performance over time.
to achieve this, i loop through the query results, and ++ a counter for the level and day the exercise was taken.
example: level 2 exercise was taken at 01.11.2015.
this.levels[2].daysAgo[1].amountTaken++;
with this, i can build a diagram, where day 0 is always today, and the performance over days is shown.
now levels[] has a predefined amount of levels, so there is no problem with that.
but daysAgo[] is very dynamic (it even changes daily with the same data), so if there was only one exercise taken, it would wander on a daily basis (from daysAgo[0] to daysAgo[1] and so on).
the daysAgo[] between that would be empty (because there are no entries).
but for evaluating the diagram, i need them to have an initialized state with amountTaken: 0, and so on.
problem being: i can't know when the oldest exercise was.
Idea 1:
First gather all entries in a kind of proxy object, where i have a var maxDaysAgo that holds the value for the oldest exercise, then initialize an array daysAgo[maxDaysAgo] that gets filled with 0-entries, before inserting the actual entries.
that seems very clumsy and overly complicated
Idea 2:
Just add the entries this.level[level].daysAgo[daysAgo].amountTaken++;, possibly leaving the daysAgo array with a lot of undefined keys.
Then, after all entries are added, i would loop over the daysAgokeys with
for (var i = 1; i < this.maxLevel; i++) { // for every level
for (var j = 0; j < this.levels[i].daysAgo.length; j++) {
but daysAgo.lengthwill not count undefined fields, will it?
So if i have one single entry at [24], length will still be 1 :/
Question:
How can I find out the highest key in an array and loop until there, when there are undefined keys between?
How can i adress all undefined keys up until the highest (and not any more)?
Or: what would be a different, more elegant way to solve this whole problem altogether?
Thanks :)
array.length returns one higher than the highest numerical index, so can be used to loop though even undefined values
as a test:
var a=[]
a[24]=1
console.log(a.length)
outputs 25 for me (in chrome and firefox).

How to determine the extrema(min&max) of a dynamic interval

I have an array of 200 in length.
Each second I have a new number added to the position [0] of the array pushing the other values up one position on the array.
What I need is to determine the max and min value for the entire array each time I feed it a new number. I need to analyze all the 200 values before a new one is fed to the array.
I've managed to do so, but I encountered some trouble discarding the 'old' max and 'old' min, since once they are pushed out of the array, I don't need them anymore.
I found a way of doing this by using the 1st differential and pushing the actual value in to another array. The problem there was that when I have a min or max appearing multiple times. This new array would have them repeated in no particular order and I want just one max and one min.
If you have an array of n values which is updated at intervals by removing the first element and pushing a new one at the end then you can split the algorithm which finds the min/max of the interval in two steps.
Your precondition allows you to make a strong assumption which is the fact that
min(data) = min(data[0], data[1..n-1])
Starting from this assumption you don't need to calculate the min/max on all values at each step.
Let's make an example, suppose like you said, to have 200 values and to have a generic min function able to calculate the minimum of an array, a pair of values or a value and an array. It's metacode, ignore the syntax.
You start by precomputing the minimum and additional support data:
int middleMin = min(array[1..n-1]); // so we skip first
int firstValue = array[0];
int realMin = min(firstValue, middleMin);
Now, when you insert a new element at the end and remove the first two things can happen:
firstValue == realMin ( && firstValue < middleMin), in this case you must find the next higher value on the new array[0..n-1] since you removed the minimum
middleMin == realMin in this case you know that the removed element wasn't the first so you don't need to recompute the global minimum, you just need to update it according to the new inserted element, eg middleMin = realMin = min(realMin, array[n-1])
actually it can also happen that firstValue == middleMin but this falls back to second case since there is another value in the trail array which is the current minimum.

using google's data.join to interatively add data to a graph

I'm trying to build a set of data for a Google scatter graph using data.join as follows:
var tempData = newData();
var tempData2 = totalData;
dataArray[dataCount] = tempData;
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],[joinMark],[1]);
dataCount = dataCount+1;
Where newData() generates a dataTable from a database, column 0 is always a date and column 1 is always a number. I have been able to get this to work once, to display 2 variables on the graph, but trying to add any more causes my code to fail.
BTW totalData is the variable passed to chart.draw()
The countArray function returns 1 if both arrays have 2 columns (works fine), but for further additions I am returning a comma separated string 1,2... 1,2,3.. etc. This is based on my assumption that that last two variables in data.join are the column numbers from dataTable 1 and 2 respectively to be combined. Am I right in this assumption, or do I need a different variable in that location?
Thanks
Tom
You are correct about the function of the last two parameters in the join call, but you do not want to pass a comma-separated string where joinMark is: that should be an array of column indices, not an array containing a string. You cannot add a comma-separated string to an array to get an array on integers:
var joinMark = '1,2,3';
[joinMark] == [1,2,3]; // false
Change your countArray function to return an array of integers instead, and then pass that array directly to the join function (that is, you shouldn't wrap it in brackets to create an array of arrays):
var joinMark = countArray(dataCount);
totalData = google.visualization.data.join(tempData2,tempData,'full',[[0,0]],joinMark,[1]);

Categories

Resources