Course outline
Full-Stack course / JavaScript fundamentals

Unique tag counter

Lab

How to fetch and submit this exercise

Once: install the tool and connect your account.

curl -fsSL https://gonomicon.com/install.sh | sh
gonomicon login

Each exercise: download it, edit the file named in the instructions, then submit.

gonomicon fetch fs-week-2/03-05-unique-tag-counter
cd 03-05-unique-tag-counter
gonomicon submit

The runner depends on the exercise: JavaScript/TypeScript/React labs run with Vitest, Python labs with pytest, and config-file labs (Docker, CI, Terraform, Nginx) are checked by parsing your file. gonomicon test runs the visible checks on your computer first; submitting also runs the hidden checks on our server.

Unique tag counter

Write two functions that look across a list of blog posts and their tags: one that collects every distinct tag used anywhere, and one that counts how many posts each tag shows up in.

Worked example

Here's a similar pair of functions for a conference's talk schedule:

const sessions = [
  { speaker: "Lee", topics: ["testing", "ci"] },
  { speaker: "Omar", topics: ["testing", "testing", "docker"] },
  { speaker: "Priya", topics: [] },
];

function allTopics(sessions) {
  const topics = new Set();
  for (const session of sessions) {
    for (const topic of session.topics) {
      topics.add(topic);
    }
  }
  return topics;
}

function topicSessionCounts(sessions) {
  const counts = new Map();
  for (const session of sessions) {
    const seen = new Set(session.topics);
    for (const topic of seen) {
      counts.set(topic, (counts.get(topic) ?? 0) + 1);
    }
  }
  return counts;
}

console.log(allTopics(sessions));
console.log(topicSessionCounts(sessions));
Set(3) { 'testing', 'ci', 'docker' }
Map(3) { 'testing' => 2, 'ci' => 1, 'docker' => 1 }

allTopics just dumps every topic it sees into one Set, so duplicates vanish automatically - Omar's two "testing" entries collapse into a single entry in the result. topicSessionCounts is counting something different: not how many times a topic appears, but how many sessions mention it at all. That's why it builds new Set(session.topics) first for each session - turning Omar's ["testing", "testing", "docker"] into just {testing, docker} before counting - so his repeated "testing" only adds 1 to the running total, not 2.

Your task

Write function uniqueTags(posts). posts is an array of objects shaped like { title, tags }, where tags is an array of strings. Return a Set containing every distinct tag used across all the posts.

Write function tagCounts(posts). Return a Map from each tag name to the number of posts that include that tag at least once - a tag repeated several times within one post's tags array should still only add 1 to that tag's count.

Rules

  • A tag that appears twice in the same post's tags array counts as appearing in that post exactly once, not twice.
  • A post with an empty tags array contributes nothing to either result.
  • Neither function changes the posts array, any post object, or any tags array.
  • uniqueTags returns a Set, and tagCounts returns a Map - not a plain array or object.

What you'll practice

Building a Set of every distinct value seen across a nested structure, and using a Map to count how many groups a value shows up in - handling duplicates within a single group correctly in both cases.

Run it

gonomicon fetch fs-week-2/03-05-unique-tag-counter
cd 03-05-unique-tag-counter
gonomicon test
gonomicon submit

Hints

  1. A Set only ever has one copy of each value, so adding the same tag to it twice does nothing - that's exactly what you want for uniqueTags.
  2. For tagCounts, the trick for 'at most once per post' is to turn each post's tags array into a Set first (new Set(post.tags)), then walk that Set instead of the raw array.
  3. counts.get(tag) ?? 0, then + 1, then counts.set(tag, ...) is the same running-total pattern you've used with a plain object, just with Map's get/set instead of bracket notation.