根据c#中的子数组过滤数组中的重复项

时间:2012-07-10 13:17:07

标签: c# linq filter iequalitycomparer

我有一个基本代码和一系列位置的人员列表。我需要消除列表中具有相同位置的不同基本代码的人员,并保留具有不同位置的人员。

我尝试使用IEqualityComparer,并在linq中分组,但我没有成功。 你能告诉我怎么做吗? 这是我的班级结构

public class Person
{
    public string Name { get; set; }

    public List<Location> Locations { get; set; }
}
public class Location
{
    public string Name { get; set; }
    public string BaseCode { get; set; }
}

数据示例

Person 1
Name : John

Locations :
      [0]  Name : India , BaseCode : "AA12"
      [1] Name : USA ,BaseCode : "AA14"
Person 2
Name : John

Locations :
      [0]  Name : India, BaseCode : "AA13"
      [1] Name : USA ,BaseCode : "AA14"
Person 3
Name : John

Locations :
      [0]  Name : India, BaseCode : "AA16"
      [1] Name : UK , BaseCode : "AA17"

我想从我的列表中过滤第2个人并保留第1个人和第3个人。请提供建议

4 个答案:

答案 0 :(得分:1)

免责声明:此解决方案并未专门处理具有不同/相同位置的相同BaseCode;你没有在要求中提到任何相关内容。

<小时/> IEqualityComparer<T>路线

此处的重要部分是IEqualityComparer<T>Person的{​​{1}}实施:

Location

class Program { static void Main(string[] args) { var p1 = new Person {Name ="John", BaseCode="AA12", Locations = new List<Location> { new Location { Name = "India" }, new Location { Name = "USA" } }}; var p2 = new Person {Name ="John", BaseCode="AA13", Locations = new List<Location> { new Location { Name = "India" }, new Location { Name = "USA" } }}; var p3 = new Person {Name ="John", BaseCode="AA14", Locations = new List<Location> { new Location { Name = "India" }, new Location { Name = "UK" } }}; var persons = new List<Person> { p1, p2, p3 }; // Will not return p2. var distinctPersons = persons.Distinct(new PersonComparer()).ToList(); Console.ReadLine(); } } public class PersonComparer : IEqualityComparer<Person> { public bool Equals(Person x, Person y) { if (x == null || y == null) return false; bool samePerson = x.Name == y.Name; bool sameLocations = !x.Locations .Except(y.Locations, new LocationComparer()) .Any(); return samePerson && sameLocations; } public int GetHashCode(Person obj) { return obj.Name.GetHashCode(); } } public class LocationComparer : IEqualityComparer<Location> { public bool Equals(Location x, Location y) { if (x == null || y == null) return false; return x.Name == y.Name; } public int GetHashCode(Location obj) { return obj.Name.GetHashCode(); } } 使用linq PersonComparer扩展名提供Except来生成两个位置列表之间的差异列表。

LocationComparer然后输入linq PersonComparer方法。

<小时/> Distinct路线

如果您需要使用IEquatable<T> 不同计入“匹配”,我认为此路由不会因为BaseCode而有效没有给你机会来区分价值观。

另一种解决方案是对类本身实施GetHashCode并覆盖IEquatable<T>GetHashCodeDistinct将遵循此实现:

Except

这导致更简单的呼叫:

public class Person : IEquatable<Person>
{
    public string Name { get; set; }
    public string BaseCode { get; set; }
    public List<Location> Locations { get; set; }

    public bool Equals(Person other)
    {
        if (other == null)
            return false;

        bool samePerson = Name == other.Name;

        // This is simpler because of IEquatable<Location>
        bool sameLocations = !Locations.Except(other.Locations).Any();

        return samePerson && sameLocations;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

public class Location : IEquatable<Location>
{
    public string Name { get; set; }

    public bool Equals(Location other)
    {
        if (other == null)
            return false;

        return Name == other.Name;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

答案 1 :(得分:0)

您可以使用IEquatable接口,并覆盖Equal和GetHashCode方法,如下所示:

在问题变更后编辑:

public class Location : IEquatable<Location>
{    
       public string Name { get; set; }     
       public string BaseCode { get; set; 

        public bool Equals(Location other)
        {
            if (Object.ReferenceEquals(other, null)) return false;

            if (Object.ReferenceEquals(this, other)) return true;
            return BaseCode.Equals(other.BaseCode);
        }

        public override int GetHashCode()
        {
            return BaseCode.GetHashCode();
        }


} 

所以,现在你可以在Person列表中使用Distinct,它只会返回不同的名称和BaseCode。

 var distinctListPerson = PersonList.Distinct().ToList();

您可以从MSDN

了解此界面

答案 2 :(得分:0)

亚当的解决方案是处理它的更“恰当”的方式。但是如果你想用LINQ来做,那么这样的事情也应该这样做(注意代码需要排序位置并将字符串作为标识符):

persons
    .GroupBy(x => x.Name)
    .SelectMany(x => x)
        .GroupBy(y => string.Concat(y.Locations.Select(z => z.Name)))
    .SelectMany(x => x
        .GroupBy(y => string.Concat(y.Locations.Select(z => z.BaseCode)))
    .Select(x => x.First());

答案 3 :(得分:0)

我很想写下面的内容。我没有检查过y.Locations.Equals()是否有效,但是为了做同样的工作而更换它应该很简单。

    List<Person> personList = new List<Person>();
    List<Person> deduplicatedPersonList = new List<Person>();
    personList.ForEach(x =>
    {
        Person existingPerson = personList.Find(y =>
        {
            if (y.Locations.Equals(x.Locations))
                return false;
            return true;
        });
        if (existingPerson == null)
            deduplicatedPersonList.Add(x);
    });