Сравнитель подстрок на Intersect - PullRequest
0 голосов
/ 12 октября 2018

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

public class MiNumeroEqualityComparer : IEqualityComparer<string> {
    public bool Equals(string x, string y) => x.Contains(y);
    public int GetHashCode(string obj) => obj.GetHashCode();
}

List<string> lst = new List<string> { "abcXdef", "abcXdef", "abcede", "aYcde" };
List<string> num = new List<string> { "X", "Y", "Z" };

var fin = lst.Intersect(num, new MiNumeroEqualityComparer());

Я ожидаю в fin: "abcXdef", "abcXdef", "aYcde"

Но это пусто,почему?

Сначала я попробовал подстроку без учета регистра с: (без успеха тоже)

public bool Equals(string x, string y) => x.IndexOf(y, StringComparison.InvariantCultureIgnoreCase) >= 0;

Но тоже пусто.

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Вы делаете пересечение между двумя списками, что даст вам общие элементы между ними.Поскольку ни один из списков не содержит идентичный элемент, вы не получите результатов.

Если вы хотите получить все элементы из lst, содержащие элемент из num, то вы можете сделать что-то вроде кода ниже, который использует метод string.Contains для фильтрации элементов из lst:

var fin = lst.Where(item => num.Any(item.Contains));

Результат:

{"abcXdef", "abcXdef","aYcde"}

В качестве альтернативы, если вы хотите выполнить запрос без учета регистра, вы можете использовать вместо него метод IndexOf:

var fin = lst.Where(item => num.Any(n => 
    item.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0));

Еслиэто трудно понять (иногда это так и есть в Linq), первый фрагмент кода, приведенный выше, является кратким способом написания следующего:

var fin = new List<string>();

foreach (var item in lst)
{
    foreach (var n in num)
    {
        if (item.Contains(n))
        {
            fin.Add(item);
            break;
        }
    }
}
0 голосов
/ 12 октября 2018

Конечно, Руфус решил вашу проблему в ответе.Но позвольте мне объяснить, почему ваш подход не работал.

Причина, по которой он приводит к пустому результату, заключается в том, что Equals(string x, string y) никогда не будет вызван.Это может вывести неравенство из метода GetHashCode.Если хэши одинаковы, он будет вызывать Equals.Другими словами, ваша логика в Equals никогда не будет выполнена.

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

class Program
{
    static void Main(string[] args)
    {
        // See I added an item at the end here to show when Equals is called
        List<string> lst = new List<string> { "abcXdef", "abcXdef", "abcede", "aYcde", "X" };
        List<string> num = new List<string> { "X", "Y", "Z" };

        var fin = lst.Intersect(num, new MiNumeroEqualityComparer()).ToList();
        Console.ReadLine();
    }
}

public class MiNumeroEqualityComparer : IEqualityComparer<string>
{
    public bool Equals(string x, string y)
    {
        Console.WriteLine("Equals called for {0} and {1}.", x, y);
        return x.Contains(y);
    }

    public int GetHashCode(string obj)
    {
        Console.WriteLine("GetHashCode alled for {0}.", obj);
        return obj.GetHashCode();
    }
}

Если вы запустите приведенный выше код, он будет вызывать Equals только для элементов, которые производят такой же хэш;так что только для "X".

См. Вывод в этой скрипке .

0 голосов
/ 12 октября 2018

Пересечение получает общие элементы из 2 коллекций.Метод Intersect здесь элегантен.Его можно использовать для многих типов элементов.

ваш результат пуст, поскольку он не является общим значением в списках.

  List<string> lst = new List<string> { "abcXdef", "abcXdef", "abcede", "aYcde" };
            List<string> num = new List<string> { "X", "Y", "abcXdef", "Z", "aYcde" };

            var fin = lst.Intersect(num);

fin >> abcXdef, aYcde

...