使用 IEqualityComparer 进行 Union

发布于 2024-11-06 22:56:30 字数 1212 浏览 5 评论 0原文

我只想从两个列表中删除重复项并将它们合并为一个列表。我还需要能够定义什么是重复项。我通过 ColumnIndex 属性定义重复项,如果它们相同,则它们是重复项。这是我采取的方法:

我找到了一个很好的示例,说明如何为代码段中只需要一次的随机情况编写内联比较器。

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 属性。

I simply want to remove duplicates from two lists and combine them into one list. I also need to be able to define what a duplicate is. I define a duplicate by the ColumnIndex property, if they are the same, they are duplicates. Here is the approach I took:

I found a nifty example of how to write inline comparers for the random occassions where you need em only once in a code segment.

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);
    }
}

Then I just have my two lists, and attempt a union on them with the comparer.

            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);

The result set however is null.

Where am I going astray?
I have already confirmed that the two lists have columns with equal ColumnIndex properties.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

随心而道 2024-11-13 22:56:30

我刚刚在测试集上运行了您的代码......并且它有效!

    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);
    }

那么...也许返回并检查您的测试数据 - 或者使用其他一些测试数据运行它?

毕竟 - 对于 Union 为空 - 这表明您的两个输入列表也为空?

I've just run your code on a test set.... and it works!

    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);
    }

So... maybe go back and check your test data - or run it with some other test data?

After all - for a Union to be empty - that suggests that both your input lists are also empty?

笑红尘 2024-11-13 22:56:30

稍微简单一点的方法:

  • 它确实保留原始顺序,
  • 并在发现重复项时忽略它们

使用链接扩展方法:

   formatIssues.Union(groupIssues).DistinctBy(x => x.ColumnIndex)

这是 来自 MoreLinq 的 DistinctBy lambda 方法

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;
        }
    }
}

A slightly simpler way:

  • it does preserve the original order
  • it ignores dupes as it finds them

Uses a link extension method:

   formatIssues.Union(groupIssues).DistinctBy(x => x.ColumnIndex)

This is the DistinctBy lambda method from 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;
        }
    }
}
煞人兵器 2024-11-13 22:56:30

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);

Would the Linq Except method not do it for you?

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文