7
\$\begingroup\$

I'm slurping up fields from an API that returns an array of fields. Each field in the array is a String that actually contains two separate fields (a number and a date). The number is enclosed in parentheses and the date is following this and a space. The following is an example of the format.

const data = [
            "(2) 2020-09-15", "(3) 2020-09-16"
        ];

I'm parsing this field and then storing the data separately in my app. I have my own numbers and dates fields that will be a String in which each number and date is separated by a newline.

I'm achieving this by doing the following.

let numbers = '', dates = numbers;

        for (let datum of data) {
            datum = datum.split(/[() ]/);
            numbers += `${datum[1]}\n`;
            dates += `${datum[3]}\n`;
        }

See an example here.

I don't particularly like this and am wondering if there's a more efficient and cleaner way to write this.

\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

Rather than declaring the variables with let (you should always prefer const) and concatenating and reassigning, consider creating arrays of numbers and dates instead, eg:

[2, 3] and ["2020-09-15", "2020-09-16"]

Then after the loop is done, join all elements by newlines.

For the regular expression, rather than split, I think match would be more appropriate. You can use \((\d+)\) (\S+):

  • \( - literal (
  • (\d+) - 1st capturing group, composed of digits
  • \) - literal )
  • - literal space
  • (\S+) - 2nd capturing group, composed of non-spaces

Then extract the 1st and 2nd capturing groups.

const data = [
  "(2) 2020-09-15", "(3) 2020-09-16"
];
const numbers = [];
const dates = [];
for (const item of data) {
  const [, number, date] = item.match(/\((\d+)\) (\S+)/);
  numbers.push(number);
  dates.push(date);
}
console.log(numbers.join('\n'));
console.log(dates.join('\n'));

\$\endgroup\$
4
  • \$\begingroup\$ I liked the let vs const post you put up. But does introducing the two arrays and pushes have any mem impact? \$\endgroup\$ Oct 5, 2020 at 15:59
  • 3
    \$\begingroup\$ Every variable has a memory impact, but unless you have tens of thousands of items or something, it's not something to worry about. In general, better for code to focus on clarity and readability first. Then, if you find the script is running too slowly, run a performance analysis to see what are the bottlenecks, and fix those bottlenecks. \$\endgroup\$ Oct 5, 2020 at 16:10
  • \$\begingroup\$ Makes sense, thanks! Any go-to performance tools that you use? \$\endgroup\$ Oct 5, 2020 at 16:22
  • 2
    \$\begingroup\$ For Node, use the --inspect flag: developer.ibm.com/technologies/node-js/articles/… then you can examine it with Chrome \$\endgroup\$ Oct 5, 2020 at 16:24
3
\$\begingroup\$

I would use something like this:

            const data = [
                "(2) 2020-09-15", "(3) 2020-09-16"
            ];

            let pairs = [];
            
            const regex = /^\((\d+)\)\s+(\d{4}-\d{2}-\d{2})$/;
            
            for (let datum of data) {
                // Idea from the previous answer:
                let pair = {};
                [, pair.number, pair.date] = regex.exec(datum);
                pairs.push (pair);
            }

            console.log(pairs);
Every pair of number and date is packed as an object. The first comma in [, pair.number, pair.date] discards the whole match, which is not needed.

Unlike the solution proposed by the question's author, the related date and number are united in one object. Also, splitting is not used, as it relies on the details of the text format that can change later and semantically better suits extracting an indefinite number of similar fragments from the text.

\$\endgroup\$
0
3
\$\begingroup\$

Edge cases

In the real world, input isn't always well-formed. What happens if there is a typo in the data? For example:

const data = [
    "(2) 2020-09-15", "(3] 2020-09-16"
];

This will lead to undefined appearing in the output for the dates. In other cases/frameworks/languages an exception might be thrown that could crash your script/program. It would be better to guard against such scenarios by throwing an Error or at least skipping addition of such data.


Variable clobbering

In the loop setup, datum is assigned each string in data:

for (let datum of data) {

The first line within the loop over-writes that variable with an array:

datum = datum.split(/[() ]/);

This is legal in JavaScript because it is loosely-typed. But think of anyone reading this code (including your future-self!) when modifying this code. What if you decide later to use datum to display the output differently - you would need to determine whether it is the datum that is a string or the datum that is an array. A separate variable name might lead to less confusion in that respect, and also provide a better hint as to what is in the array - e.g. parts, or as is suggested by CertainPerformance's answer, using destructuring assignment can help avoid that scenario altogether.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks. In regards to the overwriting of datum - are there any concerns about memory with assigning to a separate var? \$\endgroup\$ Oct 5, 2020 at 15:58
  • 1
    \$\begingroup\$ I doubt there would be much to be concerned about for such small code but going along with CertainPerformance's comment if you notice performance issues then you might want to look into the memory allocation of variables - consider eliminating variables that don't need to be assigned, or those that are only used once after being assigned. \$\endgroup\$ Oct 5, 2020 at 16:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.