diff --git a/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountChars.cs b/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountChars.cs index 2aba88c664..a38319b1de 100644 --- a/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountChars.cs +++ b/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountChars.cs @@ -1,7 +1,6 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Order; using System.Text.RegularExpressions; -using CommunityToolkit.HighPerformance; namespace CountingCharOccurences { @@ -59,10 +58,7 @@ public int CountCharsUsingIndex(string source, char toFind) int n = 0; while ((n = source.IndexOf(toFind, n) + 1) != 0) - { - n++; count++; - } return count; } @@ -130,7 +126,7 @@ public int CountCharsUsingReplace(string source, char toFind) [ArgumentsSource(nameof(GenerateStringWithCharArgs))] public int CountCharsUsingRegex(string source, char toFind) { - return new Regex(Regex.Escape(toFind.ToString())).Matches(source).Count; + return Regex.Count(source, Regex.Escape(toFind.ToString())); } [Benchmark] diff --git a/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountSubstringsAndFrequencies.cs b/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountSubstringsAndFrequencies.cs new file mode 100644 index 0000000000..9c3b23485e --- /dev/null +++ b/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountSubstringsAndFrequencies.cs @@ -0,0 +1,35 @@ +namespace CountingCharOccurences +{ + public class CountSubstringsAndFrequencies + { + public int CountSubstringNonOverlapping(string source, string toFind) + { + return source.AsSpan().Count(toFind); + } + + public int CountSubstringOverlapping(string source, string toFind) + { + var count = 0; + + for (var n = 0; (n = source.IndexOf(toFind, n, StringComparison.Ordinal)) != -1; n++) + count++; + + return count; + } + + public Dictionary CountEveryCharUsingLinq(string source) + { + return source.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count()); + } + + public Dictionary CountEveryCharUsingLoop(string source) + { + var counted = new Dictionary(); + + foreach (var c in source) + counted[c] = counted.GetValueOrDefault(c) + 1; + + return counted; + } + } +} diff --git a/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountingCharOccurences.csproj b/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountingCharOccurences.csproj index 7a93a95341..62be4f867f 100644 --- a/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountingCharOccurences.csproj +++ b/strings-csharp/CountingCharOccurences/CountingCharOccurences/CountingCharOccurences.csproj @@ -2,17 +2,13 @@ Exe - net6.0 + net10.0 enable enable - - + - - - diff --git a/strings-csharp/CountingCharOccurences/CountingCharOccurences/Program.cs b/strings-csharp/CountingCharOccurences/CountingCharOccurences/Program.cs index cf3e092698..091f7f1c4d 100644 --- a/strings-csharp/CountingCharOccurences/CountingCharOccurences/Program.cs +++ b/strings-csharp/CountingCharOccurences/CountingCharOccurences/Program.cs @@ -1,12 +1,4 @@ using BenchmarkDotNet.Running; +using CountingCharOccurences; -namespace CountingCharOccurences -{ - internal class Program - { - static void Main(string[] args) - { - BenchmarkRunner.Run(); - } - } -} \ No newline at end of file +BenchmarkRunner.Run(); diff --git a/strings-csharp/CountingCharOccurences/Test/CountSubstringsAndFrequenciesTest.cs b/strings-csharp/CountingCharOccurences/Test/CountSubstringsAndFrequenciesTest.cs new file mode 100644 index 0000000000..868dee22d2 --- /dev/null +++ b/strings-csharp/CountingCharOccurences/Test/CountSubstringsAndFrequenciesTest.cs @@ -0,0 +1,52 @@ +using CountingCharOccurences; + +namespace Test +{ + public class CountSubstringsAndFrequenciesTest + { + private static readonly CountSubstringsAndFrequencies _counter = new CountSubstringsAndFrequencies(); + + [Fact] + public void WhenCountSubstringNonOverlappingThenMatchesDoNotOverlap() + { + string main = "aaaa"; + string toFind = "aa"; + + int actual = _counter.CountSubstringNonOverlapping(main, toFind); + + Assert.Equal(2, actual); + } + + [Fact] + public void WhenCountSubstringOverlappingThenMatchesOverlap() + { + string main = "aaaa"; + string toFind = "aa"; + + int actual = _counter.CountSubstringOverlapping(main, toFind); + + Assert.Equal(3, actual); + } + + [Fact] + public void WhenCountEveryCharUsingLinqThenReturnFrequencyOfEachChar() + { + string main = "hello world"; + + var actual = _counter.CountEveryCharUsingLinq(main); + + Assert.Equal(3, actual['l']); + Assert.Equal(2, actual['o']); + } + + [Fact] + public void WhenCountEveryCharUsingLoopThenReturnSameFrequenciesAsLinq() + { + string main = "hello world"; + + var actual = _counter.CountEveryCharUsingLoop(main); + + Assert.Equal(_counter.CountEveryCharUsingLinq(main), actual); + } + } +} diff --git a/strings-csharp/CountingCharOccurences/Test/Test.cs b/strings-csharp/CountingCharOccurences/Test/Test.cs index d9ed402a86..3878f71ef8 100644 --- a/strings-csharp/CountingCharOccurences/Test/Test.cs +++ b/strings-csharp/CountingCharOccurences/Test/Test.cs @@ -50,6 +50,17 @@ public void WhenSearchCharUsingIndexThenReturnNumberOfOccurences() Assert.Equal(2, actual); } + [Fact] + public void WhenSearchCharWithAdjacentOccurencesThenReturnNumberOfOccurences() + { + string main = "LLama LLama"; + char toFind = 'L'; + + int actual = _countChars.CountCharsUsingIndex(main, toFind); + + Assert.Equal(4, actual); + } + [Fact] public void WhenSearchCharUsingForThenReturnNumberOfOccurences() { diff --git a/strings-csharp/CountingCharOccurences/Test/Test.csproj b/strings-csharp/CountingCharOccurences/Test/Test.csproj index 481e6febe7..e7256bb28b 100644 --- a/strings-csharp/CountingCharOccurences/Test/Test.csproj +++ b/strings-csharp/CountingCharOccurences/Test/Test.csproj @@ -1,7 +1,7 @@ - net6.0 + net10.0 enable enable @@ -9,13 +9,13 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all