Использование IEqualityComparer для Союза
Я просто хочу удалить дубликаты из двух списков и объединить их в один список. Мне также нужно определить, что такое дубликат. Я определяю дубликат с помощью свойства ColumnIndex, если они одинаковы, они являются дубликатами. Вот такой подход:
Я нашел отличный пример того, как писать встроенные сопоставления для случайных случаев, когда вам нужно em только один раз в сегменте кода.
public class InlineComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> getEquals;
private readonly Func<T, int> getHashCode;
public InlineComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
{
getEquals = equals;
getHashCode = hashCode;
}
public bool Equals(T x, T y)
{
return getEquals(x, y);
}
public int GetHashCode(T obj)
{
return getHashCode(obj);
}
}
Тогда у меня есть только два моих списка, и попытайтесь объединить их с компаратором.
var formatIssues = issues.Where(i => i.IsFormatError == true);
var groupIssues = issues.Where(i => i.IsGroupError == true);
var dupComparer = new InlineComparer<Issue>((i1, i2) => i1.ColumnInfo.ColumnIndex == i2.ColumnInfo.ColumnIndex,
i => i.ColumnInfo.ColumnIndex);
var filteredIssues = groupIssues.Union(formatIssues, dupComparer);
Однако набор результатов равен нулю.
Где я сбиваюсь с пути?
Я уже подтвердил, что два списка имеют столбцы с равными свойствами ColumnIndex.
Ответы
Ответ 1
Я только что запустил ваш код на тестовом наборе... и он работает!
public class InlineComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> getEquals;
private readonly Func<T, int> getHashCode;
public InlineComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
{
getEquals = equals;
getHashCode = hashCode;
}
public bool Equals(T x, T y)
{
return getEquals(x, y);
}
public int GetHashCode(T obj)
{
return getHashCode(obj);
}
}
class TestClass
{
public string S { get; set; }
}
[TestMethod]
public void testThis()
{
var l1 = new List<TestClass>()
{
new TestClass() {S = "one"},
new TestClass() {S = "two"},
};
var l2 = new List<TestClass>()
{
new TestClass() {S = "three"},
new TestClass() {S = "two"},
};
var dupComparer = new InlineComparer<TestClass>((i1, i2) => i1.S == i2.S, i => i.S.GetHashCode());
var unionList = l1.Union(l2, dupComparer);
Assert.AreEqual(3, unionList);
}
Итак... возможно, вернитесь и проверьте свои тестовые данные - или запустите его с некоторыми другими тестовыми данными?
В конце концов, для того, чтобы Союз был пустым, это означает, что оба ваших входных списка также пусты?
Ответ 2
Не будет ли метод Linq Except делать это для вас?
var formatIssues = issues.Where(i => i.IsFormatError == true);
var groupIssues = issues.Where(i => i.IsGroupError == true);
var dupeIssues = issues.Where(i => issues.Except(new List<Issue> {i})
.Any(x => x.ColumnIndex == i.ColumnIndex));
var filteredIssues = formatIssues.Union(groupIssues).Except(dupeIssues);
Ответ 3
Несколько более простой способ - и да, он сохраняет исходный порядок, удаляя 2-й и последующие обманы.
formatIssues.Union(groupIssues).DistinctBy(x => x.ColumnIndex)
Это DistinctBy
лямбда-метод от MoreLinq
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> knownKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (knownKeys.Add(keySelector(element)))
{
yield return element;
}
}
}