3
\$\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));

asked Jun 18, 2019 at 15:24
\$\endgroup\$

3 Answers 3

3
\$\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)

answered Jun 18, 2019 at 18:35
\$\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);

answered Jun 18, 2019 at 21:47
\$\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

answered Jun 18, 2019 at 18:12
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Is 'ya' Jamaican? \$\endgroup\$ Commented Jun 18, 2019 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\$ Commented Jun 18, 2019 at 18:43

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.