0

I am using this code:

class CsvParser {
  constructor(csv, field_separator = ",") {
    this.field_separator = field_separator;
    this.csv = csv;
        this.index = 0;
        this.first = true;
  }

  get_next_record(record) {
        record = this.csv.split(',');
        if(this.first) {
          this.first = false;
        } else {
          return false;
        }
        return true;
  }
}

function process_csv(contents) {

     const parser = new CsvParser(contents);
     let record = [];
     while(parser.get_next_record(record)) {
        console.log(record);
     }
     
    console.log("exiting process_csv");
}

process_csv("1,2,3");

Run via this web page:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>CsvParser demo</title>
    <script src="csvparser.js"></script>
  </head>
  <body>
  </body>
</html>

If I run this javascript, the console output is:

[]
exiting process_csv

Why does record after the calling of the get_next_record member function not populate the record?

This code is of course not complete. My idea is that get_next_record would be repeatedly called until the end of the contents was reached in which case the get_next_record function would return false.

I thought that if I try to simply return the record then how to signify that we have reached the end of the contents?

This presumably is not the way things are done in javascript. What is the idiomatic way to design the class/function in javascript? Is call by reference not supported?

6
  • 2
    Does this answer your question? Javascript function not modifying array (reference?). record = this.csv.split(','); just assigns a new value to the implicit record variable in the get_next_record function. It’s an implicit variable because it’s a parameter. Commented Jun 27, 2020 at 17:55
  • 2
    JavaScript never uses call by reference. Commented Jun 27, 2020 at 17:55
  • 1
    record = this.csv.split(','); assigns a new reference, it does not replace the value of the existing reference. Commented Jun 27, 2020 at 17:56
  • stackoverflow.com/questions/42045586/… Commented Jun 27, 2020 at 17:56
  • You're only returning bools in get_next_record. You're not even keeping track of the index. Commented Jun 27, 2020 at 17:57

2 Answers 2

1

I believe an iterator would be more appropriate for this type of control flow. You can use iterators implicitly by writing a generator function and a for...of loop to consume it:

function* records(csv, separator = ',') {
  let currIndex = 0;

  while (currIndex !== -1) {
    const nextIndex = csv.indexOf(separator, currIndex);

    if (nextIndex === -1) {
      yield csv.slice(currIndex);
      currIndex = nextIndex;
    } else {
      yield csv.slice(currIndex, nextIndex);
      currIndex = nextIndex + 1;
    }
  }
}

for (const record of records('1,2,3')) {
  console.log(record);
}

Or you can use iterators explicitly:

function records(csv, separator = ',') {
  let currIndex = 0;

  return {
    [Symbol.iterator]() {
      return this;
    },
    next() {
      if (currIndex === -1) {
        return { done: true };      
      }

      const nextIndex = csv.indexOf(separator, currIndex);

      if (nextIndex === -1) {
        const value = csv.slice(currIndex);
        currIndex = nextIndex;
        return { done: false, value };
      } else {
        const value = csv.slice(currIndex, nextIndex);
        currIndex = nextIndex + 1;
        return { done: false, value };
      }
    }
  };
}

const iter = records('1,2,3');
let result;

while (!(result = iter.next()).done) {
  console.log(result.value);
}

Note that an iterator implements the next() method, an iterable implements the [Symbol.iterator] method, and a generator object implements both. for...of will work with any generator object, even if it is implemented manually:

function records(csv, separator = ',') {
  let currIndex = 0;

  return {
    [Symbol.iterator]() {
      return this;
    },
    next() {
      if (currIndex === -1) {
        return { done: true };      
      }

      const nextIndex = csv.indexOf(separator, currIndex);

      if (nextIndex === -1) {
        const value = csv.slice(currIndex);
        currIndex = nextIndex;
        return { done: false, value };
      } else {
        const value = csv.slice(currIndex, nextIndex);
        currIndex = nextIndex + 1;
        return { done: false, value };
      }
    }
  };
}

for (const record of records('1,2,3')) {
  console.log(record);
}

Sign up to request clarification or add additional context in comments.

Comments

0

You're only returning bools in get_next_record. You're not even keeping track of the index. You're also not returning the record from anywhere in your class. You're also not splitting by newline (but I'm not sure if you're trying to). This will work on a single line:

class CsvParser {
  constructor(csv, field_separator = ",") {
    this.field_separator = field_separator;
    this.csv = csv;
        this.index = 0;
        this.first = true;
  }

  get_next_record(record) {
        record = this.csv.split(this.field_seperator);
        if(this.first) {
          this.first = false;
        } 
        this.index++;
        return record[this.index-1];
  }
}

function process_csv(contents) {

     const parser = new CsvParser(contents);
     let record;
     while(record = parser.get_next_record(record)) {
        console.log(record);
     }
     
    console.log("exiting process_csv");
}

ex:

process_csv("1,2,3");
1
2
3
exiting process_csv

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.