Context: I am successfully reading a CSV file into an array with d3. The data consists of personal IDs (which occur multiple times) and of one item (out of A, B, C, D, E, F, G) associated with the ID. I want to summarize this data in a histogram-like way: I want to create a 2D associative array, which, for every ID and every item, stores the frequency of the item in all data rows containing the ID. The IDs are not continuous from 0 to n, but rather random numbers, that's why I want to use an associative array for the first dimension, too, rather than a normal array.
The following code works and returns just what I want at the call of console.log(results), at least, when I tap the expand sign.
However, calling console.log(results[0]) does not work, where 0 is an existing key in the results array, as it should be and as I can see in the console.
There are very similar questions on SO, and the answer is to use Object.keys(results) or JSON.stringify(results). But these do not work for me, either (see code).
I am very confused. In Python or Java this would be the easiest thing in the world. Why doesn't it work in JavaScript? And how can I make it work?
var results = {};
d3.csv("data.csv", data => {
data.forEach(row => {
if (!(row["id"] in results)) {
results[row["id"]] = {"A": 0, "B": 0,"C": 0, "D": 0, "E": 0, "F": 0, "G": 0};
}
results[row["id"]][row["category"]]++;
});
});
console.log(results);
// {}
// on expansion:
// 0: {A: 1, B: 5, C: 0, D: 0, E: 0, ...}
// 1: {A: 0, B: 3, C: 0, D: 1, E: 0, ...}
// ...
console.log(results[0]);
// undefined
console.log(results["0"]);
// undefined
console.log(Object.keys(results));
// []
// on expansion:
// length: 0
console.log(JSON.stringify(results));
// {}
// not expandable
Example of data.csv:
id,category
0,A,
0,B,
0,C,
0,C,
0,C,
1,D,
2,D,
2,E,
5,A,
5,B,
5,C,
SOLUTION:
Quentin is right that this is about asynchronicity, however I'd like to point out how I adapted the specific code:
The problem has been: The console.logs are executed before the results are calculated, because forEach() is an asynchronous function and d3.csv() is also an asynchronous function. The console is funny: When I click on the expand button, the results have already been calculated because some seconds have passed.
- So, I changed the asynchronous forEach function into a normal for loop.
- As there is no synchronous CSV-function in d3, I put the rest of the data-processing code inside the d3-CSV-callback.
Code:
var results = {};
d3.csv("data.csv", data => {
for (key in Object.keys(data)) {
row = data[key];
if (!(row["id"] in results)) {
results[row["id"]] = {"A": 0, "B": 0,"C": 0, "D": 0, "E": 0, "F": 0, "G": 0};
}
results[row["id"]][row["category"]]++;
}
console.log(results);
// 0: {A: 1, B: 5, C: 0, D: 0, E: 0, ...}
// 1: {A: 0, B: 3, C: 0, D: 1, E: 0, ...}
// ...
console.log(results[0]);
// {A: 1, B: 5, C: 0, D: 0, E: 0, ...}
// do all the consequent data processing in here
});