Присоединяйтесь + IEqualityComparer<T> и HashCode
-
23-09-2019 - |
Вопрос
Я пишу свой собственный справочник по LINQ, но у меня возникают проблемы с некоторыми из более сложных реализаций операторов.
Существует реализация соединения, которая использует IEqualityComparer. Я просто схожу с ума.
Я пытаюсь сначала понять это, прежде чем писать (очевидно)
Представьте себе эти два списка:
List<string> initials = new List<string> {"A", "B", "C", "D", "E"};
List<string> words = new List<string> {"Ant", "Crawl", "Pig", "Boat", "Elephant", "Arc"};
Здесь нет ничего странного.Я хочу объединить оба списка по начальному значению, например:
Начальное значение=Слово=Муравей
Начальное значение=Слово=Дуга
Начальное значение=B Слово=Лодка
...
Мне нужен компаратор, я написал это:
public class InitialComparator : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x.StartsWith(y);
}
public int GetHashCode(string obj)
{
return obj[0].GetHashCode();
}
}
Само соединение:
var blah = initials.Join(words,
initial => initial,
word => word,
(initial, word) =>
new {Initial = initial, Word = word},
new InitialComparator());
Я впервые использую HashCodes, после хорошего сеанса отладки я вижу, что каждое слово идет в компаратор и смотрит на его HashCode, если другое слово имеет тот же HashCode, которое оно называет равным.
Поскольку я хочу сравнить только начальную букву, я подумал, что мне нужна только первая буква Хэш (я ошибаюсь?)
Дело в том, что это работает неправильно.В нем говорится, что «Ant» и «Arc» равны. Хорошо, он сравнивает каждое слово в одном списке или нет. Но он добавляет только последнее найденное слово, в данном случае Arc, игнорируя Ant и Ant, равно «A». " слишком...
Если я поставлю «Ant» и «Ant», будут добавлены оба.
Короче говоря, как это сделать?Я знаю, что делаю что-то не так.
Спасибо.
Решение
Как упомянуто хрустяние, попробуйте x [0] == y [0] вместо x.startswith (y);Это сработало для меня.
Другие советы
На самом деле вам не нужен собственный компаратор равенства, просто присоединитесь к отдельному письму следующим образом:
var mine = from i in initials join w in words on i[0] equals w[0] select new { Initial = i, Words = w };
Я не уверен, почему вы видите такое поведение, но я думаю, что использование «SelectMany» было бы более простым подходом и (что более важно) имело бы желаемое поведение:
var blah =
from word in words
from initial in initials
where (word.StartsWith(initial))
select new { Initial = initial, Word = word };
Я предпочитаю использовать синтаксис понимания, где это возможно.«SelectMany» вызывается, когда в запросе на понимание имеется несколько предложений «from».