-1

I got two JSON files that I'm processing:

  • sorted/apr-total2.json
  • sorted/may-total2.json

There are files for other months of the year, but for debugging purposes I'm focusing on these two because they are causing the problem.

They contain simple data in the following format:

[
["John", 1403],
["Peter", 1159],
...
]

However, John is available only in sorted/apr-total2.json file and not in sorted/may-total2.json.

My code is the following:

let months = ["apr", "may"];
let dataToSort = {};

function getDataFromJSONFile(month) {
  let jsonData = fs.readFileSync(`sorted/${month}-total2.json`);
  let convertedData = JSON.parse(jsonData);
  return convertedData;
}

function arrayToObject(data) {
  data.forEach((user) => {
    dataToSort[user[0].toString()] = user[1];
  });
  return dataToSort;
}

for (let i in months) {
  let currentMonth = months[i];
  console.log("Current month is " + currentMonth);
  let getDataForMonth = getDataFromJSONFile(currentMonth);
  let convertedMonth = arrayToObject(getDataForMonth);
  if (convertedMonth.hasOwnProperty("John") == true) {
    console.log(true);
  }
}

My output is the following:

Current month is apr
true
Current month is may
true

This isn't correct, since user John isn't available in sorted/may-total2.json. So why is this happening? It seems that the object convertedMonth is causing the issue.

If I add the following code at the end of the for loop and delete the ConvertedMonth object properties:

for (let item in convertedMonth) {
  delete convertedMonth[item];
}

It works as intended:

Current month is apr
true
Current month is may

I want to know why this object is causing the issue, because I reused the same code in another place of my project.

Mentalhead
  • 1,501
  • 5
  • 20
  • 28
  • 3
    Don't use `for..in` on arrays ~ [Why is using "for...in" for array iteration a bad idea?](https://stackoverflow.com/q/500504/283366) Use `for (let currentMonth of months)` – Phil Jan 05 '23 at 07:31
  • 1
    Declare `let dataToSort = {}` **inside** `arrayToObject()` so you're starting with an empty object. Otherwise, you're always appending to it. Alternately, use the very simple `const arrayToObject = (data) => Object.fromEntries(data)` – Phil Jan 05 '23 at 07:34
  • The `dataToSort` variable is shared between months. Initialise it inside `function arrayToObject` if you don't want it to be modified by both. As the code stands, it would only contain a user entry for the last month they appear in – Matt Jan 05 '23 at 07:35

1 Answers1

3

Your arrayToObject function uses a single global dataToSort, so any entries will be accumulated and overwritten there. See:

> let dataToSort = {};
> function arrayToObject(data) {
...   data.forEach((user) => {
...     dataToSort[user[0].toString()] = user[1];
...   });
...   return dataToSort;
... }
> arrayToObject([["foo", 123]])
{ foo: 123 }
> arrayToObject([["foo", 456], ["bar", 567]])
{ foo: 456, bar: 567 }

Your program simplifies to something like

let months = ["apr", "may"];

for (let currentMonth of months) {
    console.log("Current month is " + currentMonth);
    let jsonData = JSON.parse(fs.readFileSync(`sorted/${month}-total2.json`));
    let convertedMonth = Object.fromEntries(jsonData);
    if (convertedMonth["John"]) {
        console.log(true);
    }
}

which

  • uses for..of for correct and simpler iteration over the months
  • uses Object.fromEntries to convert an array of 2-arrays into a plain object (which is what your arrayToObject did)
AKX
  • 152,115
  • 15
  • 115
  • 172