First I would like to mention that there is no "natural" LINQ solution to this problem, so every standard LINQ based solution will be ugly and highly inefficient compared to a simple for loop.
However there is a LINQ "spirit" solution to this and similar problems, like the linked How to check repeated letters in a string c# or if you want for instance finding not doubles, but let say triples, quadruples etc.
The common sub problem is, given a some sequence of elements, generate a new sequence of (value, count) pair groups for the consecutive elements having one and the same value.
It can be done with a custom extension method like this (the name of the method could be different, it's not essential for the point):
public static class EnumerableEx
{
public static IEnumerable<TResult> Zip<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> resultSelector, IEqualityComparer<TSource> comparer = null)
{
if (comparer == null) comparer = EqualityComparer<TSource>.Default;
using (var e = source.GetEnumerator())
{
for (bool more = e.MoveNext(); more;)
{
var value = e.Current;
int count = 1;
while ((more = e.MoveNext()) && comparer.Equals(e.Current, value)) count++;
yield return resultSelector(value, count);
}
}
}
}
Using this function in combination with standard LINQ, one can easily solve the original question:
var s = "shhopkeeperssss";
var countDoubles = s.Zip((value, count) => count / 2).Sum();
but also
var countTriples = s.Zip((value, count) => count / 3).Sum();
or
var countQuadruples = s.Zip((value, count) => count / 4).Sum();
or the question from the link
var repeatedChars = s.Zip((value, count) => new { Char = value, Count = count })
.Where(e => e.Count > 1);
etc.
forloop also gives 5.ssssis a 3 pairs ofs, not 2, be careful :)if (s[i] == s[i - 1]) { d++; i++; }