2
\$\begingroup\$

This function converts a Javascript Object into a CSV.

var dataFromAPI = [{"name":"first"},{"name":"sec,ond"},{"name":"third 'jibberish"},{"name":"fourth, jibberish"}]

function convertToCSVandDownload(objArray) {
    var csvOutput = "";
    Object.keys(objArray).forEach(function(key) {
      if (csvOutput.length == 0) {
        csvOutput = "Index,Field Value\n";
        csvOutput = csvOutput + JSON.stringify(key) + "," + JSON.stringify(objArray[key]["name"]) + "\n";         
      } else {
        csvOutput = csvOutput + JSON.stringify(key) + "," + JSON.stringify(objArray[key]["name"]) + "\n";                 
      }
    })
    return csvOutput;
}

console.log(convertToCSVandDownload(dataFromAPI));

\$\endgroup\$
2
\$\begingroup\$

I'd like to propose a solution using flatMap. Be aware that this is definitely not a cross-browser solution.


Let's create a function that given n arguments returns a CSV line:

const row = (...args) => args.map(JSON.stringify).join(',');

console.log(row('foo'));
console.log(row('foo', 'bar'));
console.log(row('foo', 'bar', 'baz'));

Then let's use flatMap to append (or prepend) stuff while we map over an array. e.g.:

const pair = arr => arr.flatMap(n => [n, n]);

console.log(pair([1]));
console.log(pair([1, 2]));
console.log(pair([1, 2, 3]));

As you can see we can use flatMap to "add" more items as we iterate. Let's use this to add the headers during the first iteration.

Complete solution

const dataFromAPI = [
  {"name": "first"},
  {"name": "sec,ond"},
  {"name": "third 'jibberish"},
  {"name": "fourth, jibberish"}];
  

const row = (...args) => args.map(JSON.stringify).join(',');

const csv =
  dataFromAPI
    .flatMap((obj, idx) =>
      idx === 0 ?
        [row('Index', 'Field Value'), row(idx, obj.name)] :
        [row(idx, obj.name)])
    .join('\n');
    
console.log(csv);

\$\endgroup\$
1
\$\begingroup\$

Skimming through your code I believe ya may not need that if/else check within the .forEach loop...

var dataFromAPI = [{"name":"first"},{"name":"sec,ond"},{"name":"third 'jibberish"},{"name":"fourth, jibberish"}]

function convertToCSVandDownload(objArray) {
    var csvOutput = "Index,Field Value\n";
    Object.keys(objArray).forEach(function(key) {
        csvOutput = csvOutput + JSON.stringify(key) + "," + JSON.stringify(objArray[key]["name"]) + "\n";
    })
    return csvOutput;
}

console.log(convertToCSVandDownload(dataFromAPI));

... and one thing that might be an improvement may be allowing for converting other target_keys...

var dataFromAPI = [{"name":"first"},{"name":"sec,ond"},{"name":"third 'jibberish"},{"name":"fourth, jibberish"}]

function convertToCSVandDownload(objArray, target_key) {
    var csvOutput = "Index,Field Value\n";
    Object.keys(objArray).forEach(function(i) {
        csvOutput += JSON.stringify(i) + "," + JSON.stringify(objArray[i][target_key]) + "\n";
    })
    return csvOutput;
}

console.log(convertToCSVandDownload(dataFromAPI, 'name'));

... other than those two things I think you code is good, and the only other thing ya might want to consider is what ya want to do with data structures that have more layers than dataFromAPI

\$\endgroup\$
  • \$\begingroup\$ Is 'ya' Jamaican? \$\endgroup\$ – dfhwze Jun 18 at 18:36
  • \$\begingroup\$ The urbandictionary says something like "Term for "yes" used in Jamaica", but that is just something that I read online somewhere. Personally I use it for that as well as a less direct form of you, eg. "ya ya could do that', which when spoken would have a more uh like sound on the second ya. \$\endgroup\$ – S0AndS0 Jun 18 at 18:43
1
\$\begingroup\$

Description

It would appear that your current solution is a bit complicated. Using JSON.parse just to ensure that you escape , is overkill.

The overall solution can be drastically simplified as you will see in this post.

const before let and let before var

All variables should be declared by default with const. If a variable is going to be mutated then use let. Don't use var unless that is what you intended.

/// bad
var dataFromAPI = ...
/// good
const dataFromAPI = ...

note: pushing an element to a list will only mutate the array and not the variable, thus no error


Work with arrays and not with strings.

/// bad
csvOutput = "Index,Field Value\n";
/// good
const csvOutput = [
  ["Index", "Field", "Value"]
];

Function names should describe what they do.

The convertToCSVandDownload method only converts to CSV but doesn't download. Change the name to convertToCSV


Working Solution

Use Array#reduce, destructuring assignment, Array#map, Array#join and spread syntax

const dataFromAPI = [{"name":"first"},{"name":"sec,ond"},{"name":"third 'jibberish"},{"name":"fourth, jibberish"}]

function convertToCSV(data, headers) {
  return data
  .reduce((a,{name},i)=>[...a, [i, `"${name}"`]], [headers])
  .map(row=>row.join(","))
  .join("\n");
}

const res = convertToCSV(dataFromAPI, ["Index", "Field Value"]);

console.log(res)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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