繁体   English   中英

使用LINQ从类型集合中过滤重复项

[英]Filtering duplicates from a type collection using LINQ

我通过分组两个参数并根据createdate选择子组列表中的最新类型来过滤列表(使用first())。 这消除了x.application和x.externalid属性上的重复项。

var list = ((List<SomeType>)xDic)
            .GroupBy(x => new {x.Application, x.ExternalID})
            .OrderByDescending(z => z.First().CreateDate)
            .Select(y => y.First()).ToList();

我遇到的问题是定义另一个属性组合(x.application和x.externaldisplayid)来过滤和分组来获取第一个属性。

总而言之,我需要通过基于((x.application / x.externalid)OR(x.application / x.externaldisplayid))组合过滤掉任何重复项来获得一个独特的SomeTypes列表。

Example set:
{ "extID": 1234, "extDspID" : 111, "App" : "Test", "CreateDate": 2/01/2015}
{ "extID": 1234, "extDspID" : 5, "App" : "Test", "CreateDate": 1/01/2015}
{ "extID": 012, "extDspID" : 90, "App" : "Mono", "CreateDate": 6/06/2015}
{ "extID": 999, "extDspID" : 78, "App" : "Epic", "CreateDate": 8/08/2015}
{ "extID": 333, "extDspID" : 78, "App" : "Epic", "CreateDate": 8/12/2015}
{ "extID": 345, "extDspID" : 33, "App" : "Test", "CreateDate": 2/01/2015}
{ "extID": 666, "extDspID" : 33, "App" : "Test", "CreateDate": 1/01/2015}

desired result:
{ "extID": 1234, "extDspID" : 111, "App" : "Test", "CreateDate": 2/01/2015}
{ "extID": 012, "extDspID" : 90, "App" : "Mono", "CreateDate": 6/06/2015}
{ "extID": 333, "extDspID" : 78, "App" : "Epic", "CreateDate": 8/12/2015}
{ "extID": 345, "extDspID" : 33, "App" : "Test", "CreateDate": 2/01/2015}

首先,声明两个相等比较以指定您的两个条件,如下所示:

public class MyEqualityComparer1 : IEqualityComparer<SomeType>
{
    public bool Equals(SomeType x, SomeType y)
    {
        return x.Application == y.Application && x.ExternalID == y.ExternalID;
    }

    public int GetHashCode(SomeType obj)
    {
        return (obj.Application + obj.ExternalID).GetHashCode();
    }
}

public class MyEqualityComparer2 : IEqualityComparer<SomeType>
{
    public bool Equals(SomeType x, SomeType y)
    {
        return x.Application == y.Application && x.ExternalDisplayId == y.ExternalDisplayId;
    }

    public int GetHashCode(SomeType obj)
    {
        return (obj.Application + obj.ExternalDisplayId).GetHashCode();
    }
}

然后,按CreatedDate排序您的列表,然后使用Distinct过滤您的列表,如下所示:

var result = xDic
    .OrderByDescending(x => x.CreateDate)
    .Distinct(new MyEqualityComparer1())
    .Distinct(new MyEqualityComparer2());

Distinct方法应该删除后面的项目 ,因此我们应该能够依赖于我们使用OrderByDescending来确保Distinct将删除具有较新的CreatedTime

但是,由于Distinct的文档不能保证这一点,您可以使用这样的自定义不同方法:

public static class Extensions
{
    public static IEnumerable<T> OrderedDistinct<T>(this IEnumerable<T> enumerable, IEqualityComparer<T> comparer)
    {
        HashSet<T> hash_set = new HashSet<T>(comparer);

        foreach(var item in enumerable)
            if (hash_set.Add(item))
                yield return item;
    }
}

并像这样使用它:

var result = xDic
    .OrderByDescending(x => x.CreateDate)
    .OrderedDistinct(new MyEqualityComparer1())
    .OrderedDistinct(new MyEqualityComparer2());

当前接受的答案不会正确排序您的“SomeType”对象,因此不会产生您想要的结果集。

我在这里实现了一个解决方案:

https://dotnetfiddle.net/qBkIXo

我也将我的解决方案基于Distinct(请参阅此处的 MSDN文档)。 我生成哈希的方法是基于这种使用匿名类型的简洁方法,例如

public int GetHashCode(SomeType sometype)
{
 //Calculate the hash code for the SomeType.
 return new { sometype.Application, sometype.ExternalID }.GetHashCode();
}

为了获得正确的期望结果,需要应用不同组合,排序和使用的组合,例如

    var noduplicates = products.GroupBy(x => new {x.Application, x.ExternalDisplayId})
        .Select(y => y.OrderByDescending(x => x.CreateDate).First())
        .ToList()
        .Distinct(new ApplicationExternalDisplayIdComparer())
        .GroupBy(x => new {x.Application, x.ExternalID})
        .Select(y => y.OrderByDescending(x => x.CreateDate).First())
        .ToList()
        .Distinct(new ApplicationExternalIDComparer());

正如您在小提琴输出中看到的那样,这会给出您期望的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM