Byyo
Byyo

Reputation: 2243

Find the longest repetition character in String

Let's say i have a string like

string text = "hello dear";

Then I want to determine the longest repetition of coherented characters - in this case it would be ll. If there are more than one with the same count, take any.

I have tried to solve this with linq

char rchar = text.GroupBy(y => y).OrderByDescending(y => y.Count()).Select(x => x).First().Key;
int rcount = text.Where(x => x == rchar).Count();
string routput = new string(rchar, rcount);

But this returns ee. Am I on the right track?

Upvotes: 3

Views: 5997

Answers (4)

Rob
Rob

Reputation: 27357

If you prefer doing things with LINQ, you can do it fairly simply with a LINQ extension:

var text = "hello dear";
var result = string.Join("",
    text
    .GroupAdjacentBy((l, r) => (l == r)) /* Create groups where the current character is 
                                         Is the same as the previous character */
    .OrderByDescending(g => g.Count()) //Order by the group lengths
    .First()                           //Take the first group (which is the longest run)
);

With this extension (taken from Use LINQ to group a sequence of numbers with no gaps):

public static class LinqExtensions 
{
    public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(this IEnumerable<T> source, Func<T, T, bool> predicate)
    {
        using (var e = source.GetEnumerator())
        {
            if (e.MoveNext())
            {
                var list = new List<T> { e.Current };
                var pred = e.Current;
                while (e.MoveNext())
                {
                    if (predicate(pred, e.Current))
                    {
                        list.Add(e.Current);
                    }
                    else
                    {
                        yield return list;
                        list = new List<T> { e.Current };
                    }
                    pred = e.Current;
                }
                yield return list;
            }
        }
    }
}

Might be a bit overkill - but I've found GroupAdjacentBy quite useful in other situations as well.

Upvotes: 4

w.b
w.b

Reputation: 11228

Another solution using LINQ:

string text = "hello dear";
string longestRun = new string(text.Select((c, index) => text.Substring(index).TakeWhile(e => e == c))
                                   .OrderByDescending(e => e.Count())
                                   .First().ToArray());

Console.WriteLine(longestRun); // ll

It selects a sequence of substrings starting with the same repeating character, and creates the result string with the longest of them.

Upvotes: 4

Pierre-Luc Pineault
Pierre-Luc Pineault

Reputation: 9191

Although a regex or custom Linq extension is fine, if you don't mind "doing it the old way" you can achieve your result with two temporary variables and a classic foreach loop.

The logic is pretty simple, and runs in O(n). Loop through your string and compare the current character with the previous one.

If it's the same, increase your count. If it's different, reset it to 1.

Then, if your count is greater than the previous recorded max count, overwrite the rchar with your current character.

string text = "hello dear";

char rchar = text[0];
int rcount = 1;

int currentCount = 0;
char previousChar = char.MinValue;
foreach (char character in text)
{
    if (character != previousChar)
    {
        currentCount = 1;
    }
    else
    {
        currentCount++;
    }

    if (currentCount >= rcount)
    {
        rchar = character;
        rcount = currentCount;
    }

    previousChar = character;
}

string routput = new string(rchar, rcount);

It's indeed verbose, but gets the job done.

Upvotes: 4

fubo
fubo

Reputation: 45947

RegEx would be a option

string text = "hello dear";
string Result = string.IsNullOrEmpty(text) ? string.Empty : Regex.Matches(text, @"(.)\1*", RegexOptions.None).Cast<Match>().OrderByDescending(x => x.Length).First().Value;

Upvotes: 2

Related Questions