Найти количество символов, взаимных между двумя строками в C#

Я ищу метод, который будет принимать две строки и возвращать количество символов, общих для обоих, например:

"G010" и "G1820A" должны возвращать 3, так как символы G, 0 и 1 существуют в обоих.

Если символ существует дважды в обоих, они должны учитываться отдельно следующим образом:

"G12AA" и "GAA2" должны возвращать 4, поскольку символы G, A, A и 2 существуют в обоих.

Любая помощь с этим? Поиски в Google пока не слишком полезны.

9 ответов

Хорошо, как насчет этого, у него есть преимущество в том, чтобы максимизировать ленивую оценку и минимизировать манипуляции со строками

public int CommonChars(string left, string right)
{
    return left.GroupBy(c => c)
        .Join(
            right.GroupBy(c => c),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l).Count())
        .Sum(); 
}

по существу, он группирует каждую сторону по символу, а затем находит символы, у которых есть группа с обеих сторон. Подходящие группы учитываются в тандеме до тех пор, пока одна из них не закончится. Эти подсчеты суммируются для получения результата.


Было бы тривиально выполнить это для любых двух последовательностей. Увидеть ниже,

public static int CommomCount<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> comparer = null)
{
    if (sequence == null)
    {
        return 0;
    }

    if (comparer == null)
    {
        comparer = EqualityComparer<T>.Default;
    }

    return source.GroupBy(t => t, comparer)
        .Join(
            sequence.GroupBy(t => t, comparer),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l).Count(),
            comparer)
        .Sum();
}

Который вы бы использовали, как это.

"G12AA".CommonCount("GAA2")

Необязательный comparer Параметр может оказаться полезным, если вам требуется регистронезависимость или другое специальное лечение.


В интересах восстановления, я бы соблазнился удалить Sum() и вернуть IEnumerable<T>, а затем добавить сумму к звонку, как это,

public static IEnumerable<T> Commom<T>(
        this IEnumerable<T> source,
        IEnumerable<T> sequence,
        IEqualityComparer<T> comparer = null)
{
    if (sequence == null)
    {
        return Enumerable.Empty<T>();
    }

    if (comparer == null)
    {
        comparer = EqualityComparer<T>.Default;
    }

    return source.GroupBy(t => t, comparer)
        .Join(
            sequence.GroupBy(t => t, comparer),
            g => g.Key,
            g => g.Key,
            (lg, rg) => lg.Zip(rg, (l, r) => l),
            comparer)
        .SelectMany(g => g);
}

так что вы могли бы легко сделать

Console.WriteLine(new string("G12AA".Common("GAA2").ToArray()));

или просто оригинал

"G12AA".Common("GAA2").Count();

Попробуй это

    public int CommonCharacters(string s1, string s2)
    {
        bool[] matchedFlag = new bool[s2.Length];

        for (int i1 = 0; i1 < s1.Length; i1++)
        {
            for (int i2 = 0; i2 < s2.Length; i2++)
            {
                if (!matchedFlag[i2] && s1.ToCharArray()[i1] == s2.ToCharArray()[i2])
                {
                    matchedFlag[i2] = true;
                    break;
                }
            }
        }

        return matchedFlag.Count(u => u);
    }

Делаем это с Linq:

    int MyCount(string s1, string s2)
    {
        return s1.Count(c =>
                            {
                                var i = s2.IndexOf(c);
                                if (i >= 0)
                                {
                                    s2 = s2.Remove(i, 1);
                                    return true;
                                }
                                return false;
                            });
    }
        string s1 = "G12A";
        string s2 = "GAA2";
        List<char> lst1 = s1.ToList();
        List<char> lst2 = s2.ToList();
        int count = 0;
        foreach (char c in lst2)
        {
            if (lst1.Contains(c))
            {
                lst1.Remove(c);
                count++;
            }
        }
        Console.WriteLine(count);

Вы можете использовать Linq для решения этой проблемы, используя что-то вроде этого:

static void Main(string[] args)
{
    IEnumerable<char> a = "G010".ToCharArray();
    IEnumerable<char> b = "G1820A".ToCharArray();

    int commonChars = FindCommonElements(a, b).Count();
    Console.WriteLine(commonChars);

    Console.ReadLine();
}

private static T[] FindCommonElements<T>(IEnumerable<T> source, IEnumerable<T> target)
{
    ILookup<T, T> lookup2 = target.ToLookup(i => i);

    return (
      from group1 in source.GroupBy(i => i)
      let group2 = lookup2[group1.Key]
      from i in (group1.Count() < group2.Count() ? group1 : group2)
      select i
    ).ToArray();
}

commonChars будет иметь значение 3. Метод FindCommonElements был вдохновлен этим вопросом: как сделать пересечение целочисленных списков при сохранении дубликатов?

              string s1 = "aabcc";
        string s2 = "adcaa";
        int x = 0;

        var s1list = s1.ToList();
        var s2list = s2.ToList();
        for (int i=0; i<s1list.Count; i++)
        {
            var check = s1list[i];
            if (s2list.Contains(s1list[i]))
            {
                x++;
                var indexval = s2list.FindIndex(a => a == s1list[i]);
                s2list.RemoveAt(indexval);
            }
        }
        Console.WriteLine(x);
string myname = "1234";
        string yourname = "12";
        char[] sam = new char[] { };
        sam = myname.ToCharArray();
        char[] sam1 = new char[] { };
        sam1 = yourname.ToCharArray();
        int id = 0;
        int id1 = 0;
        List<string> found = new List<string>();
        List<string> found1 = new List<string>();
        foreach (char item in sam)
        {
            if (found.Contains(item.ToString()))
            {
                found.Add(item.ToString() + id);
                id++;
            }
            else
                found.Add(item.ToString());
        }
        foreach (var item in sam1)
        {
            if (found1.Contains(item.ToString()))
            {
                found1.Add(item.ToString() + id);
                id1++;
            }
            else
                found1.Add(item.ToString());
        }
        var final = found.Except(found1);
        var final2 = found1.Except(found);
        var checkingCount = final.Count() + final2.Count();
        Console.Write(checkingCount);
        Console.ReadLine();

проверить это, кстати, не эффективно. Но правильно понял.

Этот будет работать быстрее с большими входными данными, так как он не выполняет циклы вложений, а скорее зависит от хешированного поиска с использованием словаря. С другой стороны, он использует больше памяти.

 public int CommonCharacterCount(string s1, string s2)
            { 
                var r=0;
                Dictionary<char,int> s2Dict = new Dictionary<char,int>();
                foreach (var ch in s2)
                {
                    if (s2Dict.ContainsKey(ch))
                        s2Dict[ch] = s2Dict[ch]+1;
                    else s2Dict.Add(ch,1);
                }

                foreach (var c in s1)
                {
                    if (s2Dict.ContainsKey(c) && s2Dict[c]>0)
                    {
                        r++;
                        s2Dict[c] = s2Dict[c] - 1;
                    }
                }
                return r;
            }

Пожалуйста, проверьте следующий код -> src - первая строка, а chk - вторая строка

var count = 0; var i = 0; src.ToList (). ForEach ((x) => {
while (chk.Substring (i).IndexOf (x)> = 0) {
подсчитывать ++; я ++; if( i > chk.Length) перерыв; }
});

Другие вопросы по тегам