I'm trying to use d3-array to generate two summaries of an array of objects:
- What actions did each teacher perform?
- What posts did each teacher edit?
This is my current approach:
const data = [
{ post_id: 47469, action: "reply", teacher_username: "John" },
{ post_id: 47469, action: "edit", teacher_username: "John" },
{ post_id: 47468, action: "reply", teacher_username: "John" },
{ post_id: 47465, action: "reply", teacher_username: "Mary" },
{ post_id: 47465, action: "edit", teacher_username: "Mary" },
{ post_id: 47467, action: "edit", teacher_username: "Mary" },
{ post_id: 46638, action: "reply", teacher_username: "Paul" },
];
const teacherSummary = [
...d3.rollup(
data,
(x) => x.length,
(d) => d.teacher_username,
(d) => d.action
),
]
.map((x) => {
return {
teacher_username: x[0],
num_edits: x[1].get("edit") || 0,
num_replies: x[1].get("reply") || 0,
};
})
.sort((a, b) => d3.descending(a.num_edits, b.num_edits));
// [
// { "teacher_username": "Mary", "num_edits": 2, "num_replies": 1 },
// { "teacher_username": "John", "num_edits": 1, "num_replies": 2 },
// { "teacher_username": "Paul", "num_edits": 0, "num_replies": 1 }
// ]
const postIdsByTeacher = d3.rollups(
data.filter((x) => x.action === "edit"),
(v) => [...new Set(v.map((d) => d.post_id))].join(", "), // Set() is used to get rid of duplicate post_ids
(d) => d.teacher_username
);
// [
// ["John","47469"],
// ["Mary","47465, 47467"]
// ]
I'm flexible on the output format. What I'd like to optimize for is efficiency and clarity:
- Could I get both summaries in a single
rollup
call? Maybe by addingedited_post_ids
toteacherSummary
. - It seems there should be a more elegant approach to replace the
[...Map/Set]
calls
Edit: Out of curiosity, I also tried this approach using alasql. Except for the nulls in edited_post_ids
, it almost works.
sql = alasql(`
select
teacher_username,
count(case when action = 'reply' then 1 end) num_replies,
count(case when action = 'edit' then 1 end) num_edits,
array(case when action = 'edit' then post_id end) as edited_post_ids
from ?
group by teacher_username
`, [data])
// [
// { teacher_username: "John", num_replies: 2, num_edits: 1, edited_post_ids: [null, 47469, null], },
// { teacher_username: "Mary", num_replies: 1, num_edits: 2, edited_post_ids: [null, 47465, 47467], },
// { teacher_username: "Paul", num_replies: 1, num_edits: 0, edited_post_ids: [null], },
// ];