简体   繁体   中英

JavaScript count number of ocurrences in Array of Objects

I have an array of objects and I was trying to figure out how I can create a new array of objects that would display a new array of objects, but with an "occurences" field.

Here is my starting json array of objects:

const fakeJson = [
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-10",
    "Popularity": 99,
    "Country": "Canada"
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-11",
    "Popularity": 99,
    "Country": "Canada"
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "Canada"
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "China"
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "Canada"
  }

Example result of what I would like. Notice the for Country Canada, one of them has Occurences: 2 for Date_Available "2022-04-12". How would I be able to accomplish this?

const resultJSON = [
  {
    "Date_Available": "2022-04-10",
    "Popularity": 99,
    "Country": "Canada",
    "Occurrences" : 1
  },
  {
    "Date_Available": "2022-04-11",
    "Popularity": 99,
    "Country": "Canada",
    "Ocurrences" : 1
  },
  {
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "Canada",
    "Occurrences" : 2
  },
  {
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "China",
    "Occurrences" : 1
  }

Here is what I have so far. My idea was to create a temporary obj with the country name, date available and occurrence set default to 1. Then based on the Date_Available, increase by 1 every time it appeared. However, if China and Canada both have the same date, then it seems to mess up the code and does not properly print the result.

let countNameMapping = {};
let finalArr = [];

for(let i = 0; i < fakeJson.length; i++){
  let tempObj = {Country:fakeJson[i].Country, Date_Available: fakeJson[i].Date_Available, occurence: 1};
  let countryName = fakeJson[i].Country;
  let date = fakeJson[i].Date_Available;
  if(countNameMapping[date] === undefined){
    countNameMapping[countryName] = tempObj;
  } else {
    countNameMapping[date].occurence += 1;
  }
}

for(let k in countNameMapping){
  finalArr.push(countNameMapping[k])
}

console.log(finalArr)
  1. Group by a custom key, eg Date_Available + Country
  2. reduce() the result, create an array with the first object as base, then add Ocurrences , based on the amount of objects found ( .length )

 const data = [{"Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-10", "Popularity": 99, "Country": "Canada"}, {"Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-11", "Popularity": 99, "Country": "Canada"}, {"Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-12", "Popularity": 99, "Country": "Canada"}, {"Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-12", "Popularity": 99, "Country": "China"}, {"Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-12", "Popularity": 99, "Country": "Canada"}]; const grouped = data.reduce((p, c) => { const key = c.Date_Available + c.Country; (p[key] = p[key] || []).push(c); return p; }, {}); const result = Object.values(grouped).reduce((p, c) => [...p, {...c[0], Ocurrences: c.length } ], []); console.log(result)

Result:

[
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-10",
    "Popularity": 99,
    "Country": "Canada",
    "Ocurrences": 1
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-11",
    "Popularity": 99,
    "Country": "Canada",
    "Ocurrences": 1
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "Canada",
    "Ocurrences": 2
  },
  {
    "Id": 1,
    "Name": "John",
    "Age": 32,
    "Date_Available": "2022-04-12",
    "Popularity": 99,
    "Country": "China",
    "Ocurrences": 1
  }
]

you can use reduce and Object.values for that

like this

 const groupBy = (data, ...keyGroup) => Object.values(data.reduce((res, item) => { const key = keyGroup.map(k => item[k]).join('-') const existing = res[key] || {...item, occurencies: 0} return {...res, [key]: {...existing,occurencies: existing.occurencies + 1 } } }, {})) const fakeJson = [ { "Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-10", "Popularity": 99, "Country": "Canada" }, { "Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-11", "Popularity": 99, "Country": "Canada" }, { "Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-12", "Popularity": 99, "Country": "Canada" }, { "Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-12", "Popularity": 99, "Country": "China" }, { "Id": 1, "Name": "John", "Age": 32, "Date_Available": "2022-04-12", "Popularity": 99, "Country": "Canada" } ] console.log('by ID', groupBy(fakeJson, 'Id')) console.log('by Country', groupBy(fakeJson, 'Country')) console.log('by country and date', groupBy( fakeJson, 'Country', 'Date_Available'))

const json = fakeJson.reduce((prev, curr) => {
   const check = () => prev.findIndex(({ Date_Available, Country }) =>
      curr.Date_Available === Date_Available &&
      curr.Country === Country
   );

   if (
      !prev.length ||
      check() === -1
   ) prev.push({
         ...Object.fromEntries(
              Object.entries(curr).filter(([key]) => !key.match(/id|name|age/i))
         ),
         Occurences: 1
      })
   else prev[check()].Occurences++
   return prev
}, [])

console.log({ json });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM