C # Linq как сравнить две строки и сообщить о первом отличном символе, который сам по себе отличается от подстановочного знака ‘?’

#c# #linq

#c# #linq

Вопрос:

У меня есть функция, которая сравнивает две строки и сообщает о первом отличном символе:

 public static int Diff(this string str1, string str2)
{
    try
    {
        if (str1 == null || str2 == null)
            return 0;
        int index = str1.Zip(str2, (c1, c2) => c1 == c2).TakeWhile(b => b).Count();
        return index;
    }
    catch (Exception)
    {
        return 0;
    }

}
  

итак, вся магия здесь:

 int index = str1.Zip(str2, (c1, c2) => c1 == c2).TakeWhile(b => b).Count();
  

допустим, у нас есть две строки:

ВВОД,1,1,0,0,0,0,0,0,0,0,0,0

ВВОД,?,?,1,?,?,?,?,?,?,?,?,?

01234567890

итак, учитывая все символы, первый отличается? итак, ответ равен 6 (начиная с 0). Это работает правильно.

Теперь я хотел бы представить ? в качестве подстановочного символа, который поэтому должен быть пропущен, и поэтому ответ должен быть 10 (начиная с 0).

Я не знаю, как изменить приведенный выше код в выражении linq, чтобы сделать это. Я пытался int index = str1.Zip(str2, (c1, c2) => c1 == c2 amp;amp; c2!='?').TakeWhile(b => b).Count(); , но это ничего не меняет и всегда сообщает 6 вместо 9.

Я хотел бы придерживаться linq вместо прохождения (более простого) цикла for Спасибо

Комментарии:

1. c1 == c2 || c2 == '?'

Ответ №1:

Вам нужно, чтобы подстановочный знак учитывался как дополнительное возможное true условие. Поэтому вам нужно использовать ИЛИ || вместо И amp;amp; :

Не:

int index = str1.Zip(str2, (c1, c2) => c1 == c2 amp;amp; c2 != '?').TakeWhile(b => b).Count();

Вместо:

int index = str1.Zip(str2, (c1, c2) => c1 == c2 || c2 == '?').TakeWhile(b => b).Count();

Вы можете добавить дополнительный || к выражению, если вы также хотите игнорировать подстановочные знаки в первом вводе.

Ответ №2:

Я думаю, вам просто нужно немного изменить логическое условие.

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

Итак, условие должно быть:

 !(c1 != c2 amp;amp; (c1 != '?' || c2 != '?'))
  

Очевидно, что это можно упростить, используя законы Деморгана:

 c1 == c2 || c1 != '?' || c2 != '?'
  

Поэтому строка становится:

 index = str1.Zip(str2, (c1, c2) => c1 == c2 || c1 != '?' || c2 != '?').TakeWhile(b => b).Count();
  

Ответ №3:

используя linq, поиграйте здесь.

 var index = c1.Zip(c2, (a, b) => new { a, b })
            .Select((p, i) => new { p.a, p.b, i })
            .Where(p => p.b != wildcard)
            .FirstOrDefault(p => p.a != p.b)?.i;
  

Ответ №4:

Вот полностью протестированное решение :

             string input1 = "1,1,0,0,0,0,0,0,0,0,0,0";
            string input2 = "u003F,u003F,1,u003F,u003F,u003F,u003F,u003F,u003F,u003F,u003F,u003F";

            int results = input1.Select((x, i) => new { chr = x, index = i }).Where(x => (x.chr != input2[x.index]) amp;amp; (x.chr != 'u003F') amp;amp; (input2[x.index] != 'u003F')).Min(x => x.index);