问题
The following
$.ajax({
url: "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv",
success: function(csv) {
const output = Papa.parse(csv, {
header: true, // Convert rows to Objects using headers as properties
});
if (output.data) {
console.log(output.data);
} else {
console.log(output.errors);
}
},
error: function(jqXHR, textStatus, errorThrow){
console.log(textStatus);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"></script>
Gives
[
{
"Province/State": "Anhui",
"Country/Region": "Mainland China",
"Lat": "31.8257",
"Long": "117.2264",
"1/22/20": "1",
"1/23/20": "9",
"1/24/20": "15",
"1/25/20": "39",
"1/26/20": "60",
"1/27/20": "70",
"1/28/20": "106",
"1/29/20": "152",
"1/30/20": "200",
"1/31/20": "237",
"2/1/20": "297",
"2/2/20": "340",
"2/3/20": "408",
"2/4/20": "480",
"2/5/20": "530"
},
{
"Province/State": "Beijing",
"Country/Region": "Mainland China",
"Lat": "40.1824",
"Long": "116.4142",
"1/22/20": "14",
"1/23/20": "22",
"1/24/20": "36",
"1/25/20": "41",
"1/26/20": "68",
"1/27/20": "80",
"1/28/20": "91",
But the dates are single objects that I need and the number next to it too, so I'd need something like
{
"Province/State": "Beijing",
"Country/Region": "Mainland China",
"Lat": "40.1824",
"Long": "116.4142",
"cases": [
{
"date": "1/28/20",
"people": "91",
],
"date": "1/29/20",
"people": "99",
],
"date": "1/30/20",
"people": "101",
],
},
Literally I'm looking for a properly formatted json with single objects
回答1:
You cannot have multiple properties with the same name like this:
{
"date": {["1/22/20", "people": "22]"},
"date": {["1/23/20", "people": "45]"}
}
Plus, ["people": "45"]
is not valid JSON. Only the last one declared would exist in the end. But you could do this:
{
"Province/State": "Beijing",
"Country/Region": "Mainland China",
"Lat": "40.1824",
"Long": "116.4142",
"dataset":[
{"date": "1/22/20", "people": 22},
{"date": "1/23/20", "people": 45}
]
}
$.ajax({
url: "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv",
success: function(csv) {
const output = Papa.parse(csv, {
header: true, // Convert rows to Objects using headers as properties
dynamicTyping: true, // Convert some fields to Numbers automatically
});
if (output.data) {
const formatted = output.data.map(area => {
const obj = { dataset: [] };
Object.keys(area).forEach(key => {
if (/^\d+\/\d+\/\d+$/.test(key)) {
obj.dataset.push({ date: key, people: area[key] });
} else {
obj[key] = area[key];
}
});
return obj;
});
document.body.innerHTML = `<pre>${JSON.stringify(formatted, 0, 2)}</pre>`;
} else {
console.log(output.errors);
}
},
error: function(jqXHR, textStatus, errorThrow){
console.log(textStatus);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"></script>
回答2:
You want to separate out the comma-separated lines into
(1) labels for the object (items 0-4)
(2) number of people (items 5+)
When iterating over a line, slice the label values off first, then create a "prototype" object for the labels. Then iterate over the people and push an object to the output for each. To get the day label to use, take the index of the "people" being iterated over, and look it that index (plus 4) on the array of labels:
jQuery.ajax({
url: "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv",
type: 'get',
dataType: 'text',
success: function(data) {
const lines = data.split('\n');
const labelKeys = lines.shift().split(',');
const output = [];
for (const line of lines) {
const cases = [];
const items = line.split(',');
const labelValues = items.slice(0, 4);
const peopleArr = items.slice(4);
const doc = {};
for (let i = 0; i < 4; i++) {
doc[labelKeys[i]] = labelValues[i];
}
peopleArr.forEach((people, i) => {
const date = labelKeys[i + 4];
cases.push({ date, people });
});
output.push({ ...doc, cases });
}
console.log(output.slice(0, 4));
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
回答3:
If you're not sure if the data format will include key changes then you should not rely on knowing all of the keys (ie. maybe they add "quarantined: true" to the JSON response). Instead you can check to see if a key is a date value or not using isNaN( Date.parse(key) )
.
The following code won't "miss" added key:value pairs.
$.ajax({
url: "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv",
success: function(csv) {
const output = Papa.parse(csv, {
header: true, // Convert rows to Objects using headers as properties
});
if (output.data) {
const covidArray = [];
output.data.forEach( function(item,index){
let covid = new Object;
covid.Cases = [];
for(let key in item) {
// Check if the key is a date or not
if(isNaN(Date.parse(item[key]))){
covid[key] = item[key];
} else {
covid.Cases.push( { "date" : key, "people" : item[key] } );
}
}
covidArray.push(covid);
});
// The whole array reformatted
console.log(covidArray);
} else {
console.log(output.errors);
}
},
error: function(jqXHR, textStatus, errorThrow){
console.log(textStatus);
}
});
回答4:
You can postprocess the CSV data by putting anything that looks like a date into a dates array instead:
for (const row of output.data) {
row.cases = []
for (const [key, value] of Object.entries(row)) {
if (key.match(/^\d+\/\d+\/\d+$/)) { // Is of format #/#/#
delete row[key]
row.cases.push({ date: key, people: Number(value) })
}
}
}
Afterwards, output.data
will have the format you want.
回答5:
You can re-construct the object and use regex to check if the property name is a date format, and do the manipulation accordingly:
$.ajax({
url: "https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_19-covid-Confirmed.csv",
success: function(csv) {
const output = Papa.parse(csv, {
header: true, // Convert rows to Objects using headers as properties
});
if (output.data) {
//console.log(output.data);
output.data = output.data.slice(0, 3); // ONLY DO 3 entries here in the demo because it is a huge array
let newData = [];
output.data.forEach(place => {
const newPlace = {};
newPlace.cases = [];
for (p in place) {
if ((/^\d+\/\d+\/\d+$/).test(p)) {
newPlace.cases.push({
date: p, count: place[p]
});
} else {
newPlace[p] = place[p];
}
}
newData.push(newPlace);
});
console.log(newData);
} else {
console.log(output.errors);
}
},
error: function(jqXHR, textStatus, errorThrow) {
console.log(textStatus);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"></script>
来源:https://stackoverflow.com/questions/60583604/how-to-split-and-create-single-objects-in-json