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?

Angus Comber
  • 9,316
  • 14
  • 59
  • 107
  • 2
    Does this answer your question? [Javascript function not modifying array (reference?)](https://stackoverflow.com/questions/33308339/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. – Sebastian Simon Jun 27 '20 at 17:55
  • 2
    JavaScript never uses call by reference. – Bergi Jun 27 '20 at 17:55
  • 1
    `record = this.csv.split(',');` assigns a new reference, it does not replace the value of the existing reference. – Patrick Roberts Jun 27 '20 at 17:56
  • https://stackoverflow.com/questions/42045586/whats-the-difference-between-a-boolean-as-primitive-and-a-boolean-as-property-o/42045636#42045636 – Scott Marcus Jun 27 '20 at 17:56
  • You're only returning bools in `get_next_record`. You're not even keeping track of the index. – Mike Furlender Jun 27 '20 at 17:57
  • https://stackoverflow.com/questions/50840293/setting-a-variable-equal-to-another-variable/50840423#50840423 – Scott Marcus Jun 27 '20 at 17:58

2 Answers2

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);
}
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
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
Mike Furlender
  • 3,869
  • 5
  • 47
  • 75