How it works
A frequency map associates each key with the number of times it appears. A dictionary is a natural representation because each new observation can look up and update one counter. Compared with repeatedly counting the entire input for each distinct value, this approach makes the relationship between input processing and accumulated state explicit and avoids unnecessary repeated scans.
The key comparer decides which observations belong in the same bucket. For a case-insensitive machine category, construct the dictionary with OrdinalIgnoreCase so both lookup and insertion use that rule. The dictionary stores the first key spelling associated with a logical key in this example; presentation may therefore need a separate canonical-label policy if consistent capitalization matters.
Walk through the example. The batch contains red, blue, Red, and green. TryGetValue supplies the previous count when a key exists and zero when it does not. Updating the indexed value creates or replaces that counter. The two red spellings share one bucket, producing a count of two. Ordering the key-value pairs before printing gives the report a predictable alphabetical order.
Watch the boundary. A dictionary indexer used for reading throws when a key is absent. The assignment form can create a key, but that does not make an earlier read safe. Use TryGetValue for the combined existence-and-read step. Also choose a counter type with enough range for the domain, and be deliberate about whether empty or whitespace-only category labels should form their own bucket.
Practice independently. Count words from a prepared array after applying an explicit trimming policy. Decide whether case variants share a bucket, then report the three most frequent words with an alphabetical tie-breaker. Test an empty batch, one repeated word, and two words with equal counts. Explain why a set would answer a different question even though it also identifies distinct words.
A working example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
foreach (string color in new[] { "red", "blue", "Red", "green" })
{
counts.TryGetValue(color, out int previous);
counts[color] = previous + 1;
}
foreach (var item in counts.OrderBy(x => x.Key, StringComparer.Ordinal))
Console.WriteLine($"{item.Key}:{item.Value}");
Expected output
blue:1 green:1 red:2
TryGetValue reads an existing counter safely; choose the comparer when constructing the map.