Zliczanie liter w tekście — Zadanie rekrutacyjne #9

Czego szuka rekruter:
Dictionary<T,int>, LINQGroupBy, obsługa wielkości liter i znaków
Poziom: Junior
Zadanie
Napisz funkcję, która liczy wystąpienia każdego znaku (lub litery) w podanym tekście i zwraca wyniki posortowane od najczęstszego.
Czego szuka rekruter
To zadanie o wzorcu zliczania z Dictionary — fundamentalny pattern w algorytmice. Rekruter sprawdza:
- Znajomość
Dictionary<char, int>lubDictionary<char, int>zGetValueOrDefault - Czy kandydat pyta o szczegóły: tylko litery czy wszystkie znaki? Wielkość liter?
- Czy zna LINQ
GroupByjako alternatywę - Co zwrócić —
Dictionary, posortowane pary, lista wynikowa?
Decyzje projektowe do omówienia z rekruterem
1. Litery tylko czy wszystkie znaki (spacje, cyfry, interpunkcja)?
2. Case-sensitive? ("A" i "a" liczone razem czy osobno?)
3. Wynik posortowany po częstości czy alfabetycznie?
4. Co dla null/pustego stringa?
✅ Rozwiązanie z Dictionary
static Dictionary<char, int> CountCharacters(string text, bool ignoreCase = true)
{
if (string.IsNullOrEmpty(text))
return new Dictionary<char, int>();
var counts = new Dictionary<char, int>();
foreach (char c in text)
{
// Opcjonalnie: pomijaj spacje i interpunkcję
// if (!char.IsLetter(c)) continue;
char key = ignoreCase ? char.ToLowerInvariant(c) : c;
counts[key] = counts.GetValueOrDefault(key) + 1;
}
return counts;
}
// Posortowane wyniki:
static IEnumerable<(char Char, int Count)> CountSorted(string text)
=> CountCharacters(text)
.OrderByDescending(kv => kv.Value)
.ThenBy(kv => kv.Key)
.Select(kv => (kv.Key, kv.Value));
// Użycie:
foreach (var (ch, count) in CountSorted("programowanie"))
Console.WriteLine($"'{ch}': {count}");
// 'a': 3
// 'o': 2
// 'e': 1
// 'g': 1
// ...
GetValueOrDefault(key) zwraca 0 jeśli klucz nie istnieje — eliminuje potrzebę sprawdzania ContainsKey.
Alternatywa — LINQ GroupBy
static IEnumerable<(char Char, int Count)> CountWithLinq(string text, bool ignoreCase = true)
{
if (string.IsNullOrEmpty(text))
return Enumerable.Empty<(char, int)>();
return text
.Select(c => ignoreCase ? char.ToLowerInvariant(c) : c)
.GroupBy(c => c)
.OrderByDescending(g => g.Count())
.Select(g => (g.Key, g.Count()));
}
Czytelniejsze ale mniej wydajne — Count() wywołane wielokrotnie. Możesz użyć g.Count() raz i zapisać.
Wersja tylko dla liter (pomijanie cyfr, spacji, interpunkcji)
static Dictionary<char, int> CountLettersOnly(string text)
{
var counts = new Dictionary<char, int>();
foreach (char c in text ?? string.Empty)
{
if (!char.IsLetter(c)) continue;
char lower = char.ToLowerInvariant(c);
counts[lower] = counts.GetValueOrDefault(lower) + 1;
}
return counts;
}
Testy jednostkowe
[Fact]
public void CountCharacters_IgnoresCase_MergesLetters()
{
var result = CountCharacters("AaB");
Assert.Equal(2, result['a']);
Assert.Equal(1, result['b']);
}
[Fact]
public void CountCharacters_EmptyString_ReturnsEmptyDictionary()
{
Assert.Empty(CountCharacters(""));
}
[Fact]
public void CountCharacters_CountsCorrectly()
{
var result = CountCharacters("aabbbc");
Assert.Equal(2, result['a']);
Assert.Equal(3, result['b']);
Assert.Equal(1, result['c']);
}
[Fact]
public void CountSorted_ReturnsOrderedByFrequency()
{
var sorted = CountSorted("aabbc").ToList();
Assert.Equal('a', sorted[0].Char);
Assert.Equal(2, sorted[0].Count);
}
Co powiedzieć na rozmowie
“Dictionary<char, int> z GetValueOrDefault jest wzorcem zliczania — prosty i O(n). Przed napisaniem pytam o szczegóły: czy liczymy wszystkie znaki czy tylko litery, czy case-sensitive, jak sortować wyniki. To pokazuje że myślę o wymaganiach zanim zacznę kodować.”
Podsumowanie
Wzorzec: counts[key] = counts.GetValueOrDefault(key) + 1. Stary idiom ContainsKey + Add/increment to dwie operacje zamiast jednej. LINQ GroupBy jest alternatywą, ale warto wiedzieć jak to działa pod spodem.
17 comments
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →
Very nice post. I absolutely appreciate this site. Keep writing!
bardzo dobry artykuł, dzieki
dzieki
takiego materiału szukałem!!!!
I am continually invstigating online for tips that can assist me. Thank you!
Thank you for this nice article
Thank you for this nice article
Jestem pod wrażeniem Twojej umiejętności przekazywania trudnych koncepcji w przystępny sposób
Świetny balans między teorią a praktyką. Dzięki temu artykułowi czuję, że naprawdę zrozumiałem temat
Nice blog! Thanks you all star articles good story!
good job keep it up
Dobra robota, Twój sposób myślenia naprawdę mnie inspiruje. Dzięki za dzielenie się swoją perspektywą
Dzięki za przypomnienie o ważnym zagadnieniu. Czasem łatwo o tym zapomnieć, a to naprawdę istotny aspekt programowania
Masz zdolność tłumaczenia skomplikowanych koncepcji na prosty język. Świetne
Twoje doświadczenie widać w każdym zdaniu. Inspirujące
Bardzo klarownie wyjaśnione! Dzięki za świetny artykuł
Masz talent do tłumaczenia skomplikowanych koncepcji na prosty język. To cecha, której wielu czytelników szuka