Compare strings for equality

I want to compare a set of strings and return equal parts until there is not an equal part. (and remove the simplest spaces).

Example:

List<string> strList = new List<string>
{
    "string xyz stop",
    "string abc stop",
    "string   qrt stop"
};

string result = GetEqualName(strList); // This should return "string"

      

I made the following method which works

string GetEqualName(IEnumerable<string> strList)
{
    string outString = "";
    bool firstTime = true;
    foreach (var subString in strList)
    {
        if (firstTime)
        {
            outString = subString;
            firstTime = false;
        }
        else
        {
            string stringBuilder = "";
            for (int i = 0; i < outString.Count(); i++)
            {
                if (outString[i] == subString[i])
                    stringBuilder = stringBuilder + outString[i];
                else
                    break;
            }
            outString = stringBuilder;
        }
    }
    outString = outString.TrimEnd(' '); // Remove traling whitespace
    return outString;
}

      

I just feel like this is something that can be done in a few lines and I'm overdoing it. Do you have any suggestions?

+3


source to share


4 answers


You can Zip

two strings together, take pairs that are equal, and then create a string of those characters.

public static string LargestCommonPrefix(string first, string second)
{
    return new string(first.Zip(second, Tuple.Create)
        .TakeWhile(pair => pair.Item1 == pair.Item2)
        .Select(pair => pair.Item1)
        .ToArray());
}

      



Once you solve the problem for concatenating two strings, you can easily apply it to a sequence of strings:

public static string LargestCommonPrefix(IEnumerable<string> strings)
{
    return strings.Aggregate(LargestCommonPrefix);
}

      

+6


source


This little feature is basically the same as your version, but shorter.



string GetEqualName(IEnumerable<string> strList)
{
    int limit = strList.Min(s => s.Length);

    int i = 0;
    for (; i < limit; i++)
    {
        if (strList.Select(s => s.Substring(0,i+1)).Distinct().Count() > 1)
        {
            break;
        }
    }
    return strList.First().Substring(0, i).Trim();
}

      

+2


source


Here's another method that does what you want. I am looking for the longest common substring from left to right using HashSet<string>

:

string GetCommonStartsWith(IEnumerable<string> strList, StringComparer comparer = null)
{
    if(!strList.Any() || strList.Any(str => string.IsNullOrEmpty(str)))
        return null;
    if(!strList.Skip(1).Any())
        return strList.First(); // only one

    if(comparer == null) comparer = StringComparer.CurrentCulture;
    int commonLength = strList.Min(str => str.Length);

    for (int length = commonLength; length > 0; length--)
    {
        HashSet<string> duptester = new HashSet<string>(comparer);
        string first = strList.First().Substring(0, length).TrimEnd();
        duptester.Add(first);
        bool allEqual = strList.Skip(1)
            .All(str => !duptester.Add(str.Substring(0, length).TrimEnd()));
        if (allEqual)
            return first;
    }
    return null;
}

      

+1


source


Here's a version that uses less LINQ than some of the other answers, and might be more efficient.

string GetEqualName(IEnumerable<string> strList)
{
    StringBuilder builder = new StringBuilder();
    int minLength = strList.Min(s => s.Length);

    for (int i = 0; i < minLength; i++)
    {
        char? c = null;
        foreach (var s in strList)
        {
            if (c == null)
                c = s[i];
            else if (s[i] != c)
                return builder.ToString().TrimEnd();
        }
        builder.Append(c);
    }
    return builder.ToString().TrimEnd();
}

      

+1


source







All Articles