Home > Blockchain >  How do I group by date and add a count if there are duplicates?
How do I group by date and add a count if there are duplicates?

Time:02-01

I have a dataset like this:

[
    {
        "Happy": 1,
        "createdAt": "2021-12-20"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-14"
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-13",
        "Anxious": 1
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-13",
        "Anxious": 1
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-09",
        "Anxious": 1
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-09",
        "Anxious": 1
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-09"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    }
]

What I want to do is group this by createdAt and if there are duplicates keys within said date, add the duplicates together. For example:

    {
        "Energetic": 1,
        "createdAt": "2021-12-13",
        "Anxious": 1
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-13",
        "Anxious": 1
    },

will be

{
  'Tired': 2,
  'Anxious': 2,
  'createdAt': '2021-12-13'
}

Another example:

    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    }

will look like

{
  'Sad': 3,
  'Anxious': 7,
  'Happy': 5,
  'Tired': 2,
  'Energetic': 1,
  'createdAt': '2021-12-08',
}

I was able to get the dataset like this so far:

response.value.reduce((acc, val) => {
  acc[toMoodMap(val) as string] = acc[val] === undefined ? 1 : (acc[val]  = 1);
  acc['createdAt'] = assessment.createdAt;
  moodArr.push(acc);
  return acc;
}, {});

I'm aware of lodash's groupBy, but it's currently not available to me unfortunately. Is there a way to achieve the end result?

CodePudding user response:

  • Using Array#reduce, iterate over the array while updating a Map where createdAt is the key and the grouped object is the value.
    • In every iteration, using Map#get, get the map value which key is the current createdAt, otherwise a fallback object with createdAt.
    • Using Object#entries and Array#forEach, iterate over the rest of the current object's properties and increment the values.
    • Using Map#set, update the current pair.
  • Using Map#values, return the list of grouped objects by createdAt.

const arr = [ { "Sad": 1, "createdAt": "2021-12-08" }, { "Happy": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" }, { "Happy": 1, "createdAt": "2021-12-08" }, { "Tired": 1, "createdAt": "2021-12-08" }, { "Energetic": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" }, { "Happy": 1, "createdAt": "2021-12-08" }, { "Sad": 1, "createdAt": "2021-12-08" }, { "Happy": 1, "createdAt": "2021-12-08" }, { "Happy": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" }, { "Sad": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" }, { "Tired": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" }, { "Anxious": 1, "createdAt": "2021-12-08" } ];

const res = [...
  arr.reduce((map, { createdAt, ...e }) => {
    const current = map.get(createdAt) ?? { createdAt };
    Object.entries(e).forEach(([key, value]) => current[key] = (current[key] ?? 0)   value);
    map.set(createdAt, current);
    return map;
  }, new Map)
  .values()
];

console.log(res);

CodePudding user response:

You were doing correct! You just want to obtain array from the final grouped object using Object.values rather than pushing it inside .reduce itself.

const arr = [
    ... Your Array
];

groupedItems = arr.reduce((acc, curr) => {

    const key = curr["createdAt"];

    if (!acc[key]) acc[key] = {}

    for (let i in curr) {
        if (i === "createdAt") {
            acc[key][i] = curr[i]
        } else {
            acc[key][i] = (acc[key][i] || 0)   1
        }
    }

    return acc;
}, {});

console.log(Object.values(groupedItems))

CodePudding user response:

I would do this manually.

First, break it down by extracting all the different createdAt's (into a set to avoid duplicates). Then, for each createdAt, get all the existing keys. For each key, count the occurrences.

Here is the beginning of the code, how I would do it. I hope this already helps, I have no time to finish that code up right now, but let me know it you are able to do it with this approach.

Code:

const data = [
    {
        "Happy": 1,
        "createdAt": "2021-12-20"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-14"
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-13",
        "Anxious": 1
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-13",
        "Anxious": 1
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-09",
        "Anxious": 1
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-09",
        "Anxious": 1
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-09"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Energetic": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Happy": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Sad": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Tired": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    },
    {
        "Anxious": 1,
        "createdAt": "2021-12-08"
    }
]

const createdAts = new Set()
data.forEach(datum => {
    createdAts.add(datum.createdAt);
});

const dataTranformed = [];

createdAts.forEach(createdAt => {
    // This array contains all data entries, for one createdAt-date
    const dataFiltered = data.filter((datum) => datum.createdAt === createdAt);
    
    // Here you will have to create a new object and add all the keys & values from dataFiltered (&increment numbers if an key already exists)
    // Add this Object to the dataTransformed list and you are done
});

CodePudding user response:

assuming your array is called data:

// let's create an object with keys equals to all created dates, values are all items with that date.
const grouped = Object.values(data.reduce((res, item) => {
  const groupedItem = Object.keys(item).reduce((group, key) => {
    if (key === 'createdAt') {
      return group;
    }
    const value = item[key];
    if (isNaN(value)) { // if the value is not a number
      return group;
    }
    return {
      ...group,
      [key]: (group[key] || 0)   value,
    };
  }, res[item.createdAt] || {createdAt: item.createdAt});
  

  return {
    ...res,
    [item.createdAt]: groupedItem,
  };
}, {}));

console.log(grouped);

CodePudding user response:

You could group by destructured createdAt and collect count for each key/value pair of the rest object.

const
    data = [{ Happy: 1, createdAt: "2021-12-20" }, { Tired: 1, createdAt: "2021-12-14" }, { Energetic: 1, createdAt: "2021-12-13", Anxious: 1 }, { Energetic: 1, createdAt: "2021-12-13", Anxious: 1 }, { Tired: 1, createdAt: "2021-12-09", Anxious: 1 }, { Tired: 1, createdAt: "2021-12-09", Anxious: 1 }, { Sad: 1, createdAt: "2021-12-09" }, { Sad: 1, createdAt: "2021-12-08" }, { Happy: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }, { Happy: 1, createdAt: "2021-12-08" }, { Tired: 1, createdAt: "2021-12-08" }, { Energetic: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }, { Happy: 1, createdAt: "2021-12-08" }, { Sad: 1, createdAt: "2021-12-08" }, { Happy: 1, createdAt: "2021-12-08" }, { Happy: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }, { Sad: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }, { Tired: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }, { Anxious: 1, createdAt: "2021-12-08" }],
    result = Object.values(data.reduce((r, { createdAt, ...o }) => {
        r[createdAt] ??= { createdAt };
        Object
            .entries(o)
            .forEach(([k, v]) => r[createdAt][k] = (r[createdAt][k] || 0)   v);
        return r;
    }, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

lets say your this is your array below

let arr = [ ... ]; 

Then we filter the object with date grouped as keys

const g = arr.reduce((a, c) => {
  let date = c.createdAt;
  if(!a[date]) {
    a[date] = [];
  }
  a[date].push(c);
  return a;
}, {});

return the filtered object as array with the generated array...

const groupedByDate = Object.keys(g).map(dt => {
  return { date:dt, values: g[dt] };
});

console.log(groupedByDate);
  •  Tags:  
  • Related