3

.NET的求复杂类型集合的差集、交集、并集 - 清风不在已徐来

 2 years ago
source link: https://www.cnblogs.com/wslpf/p/16527639.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

.NET的求复杂类型集合的差集、交集、并集

如标题所述,在ASP.NET应用程序开发中,两个集合做比较时 我们使用微软IEnumerable封装的 Except/Intersect/Union 取 差集/交集/并集 方法是非常的方便的;

但以上对于不太熟悉的小伙伴来讲,在遇到求包含引用类型(不包含string)集合时就非常的苦恼;

下面我将带着大家去了解如何通过微软自带方法方式去取**复杂类型集合**的差集、交集、并集。

这里是场景,我有以下两个学生集合。

namespace Test2
{
    internal class Program
    {
        public void Main()
        {
            //列表1
            List<Student> StudentList1 = new List<Student>()
            {
                  new Student {Id=1,Name="小明",Age=27  },
                  new Student {Id=3,Name="大郭",Age=28  },
                  new Student {Id=4,Name="老登",Age=29  }
             };
            List<Student> StudentList2 = new List<Student>()
            {
                 new Student {Id=1,Name="小明",Age=27  },
                 new Student {Id=3,Name="大郭",Age=28  },
                 new Student {Id=4,Name="老登",Age=29 },
                 new Student {Id=4,Name="小路",Age=28 },
                 new Student {Id=4,Name="小明",Age=30 }
             };

        }
    }
}

 生成两个实体集合;

下面我们取交集/差集/并集

完整调用示例(.NET Core):

namespace Test2
{
    internal class Program
    {
        public static void Main()
        {
            //列表1
            List<Student> StudentList1 = new List<Student>()
            {
                  new Student {Id=1,Name="小明",Age=27  },
                  new Student {Id=2,Name="大郭",Age=28  },
                  new Student {Id=3,Name="老登",Age=29  }
             };
            //列表2
            List<Student> StudentList2 = new List<Student>()
            {
                 new Student {Id=1,Name="小明",Age=27  },
                 new Student {Id=2,Name="大郭",Age=28  },
                 new Student {Id=3,Name="老登",Age=29 },
                 new Student {Id=4,Name="小路",Age=28 },
                 new Student {Id=5,Name="小明",Age=30 }

             };
            //取比列表1里多出来的学生数据 并输出
            var ExceptData = StudentList2.Except(StudentList1);
            Console.WriteLine("差集:" + String.Join(";", ExceptData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

            //取列表1与列表2里共有的学生数据
            var IntersectData = StudentList1.Intersect(StudentList2);
            Console.WriteLine("交集:" + String.Join(";", IntersectData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

            //获取办理所有学生的数据(一个相同的学生只能一条)
            var UnionData = StudentList1.Union(StudentList2);
            Console.WriteLine("并集:"+String.Join(";", UnionData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

        }

    }
}

  差集:1-小明-27;2-大郭-28;3-老登-29;4-小路-28;5-小明-30
  交集:null
  并集:1-小明-27;2-大郭-28;3-老登-29;1-小明-27;2-大郭-28;3-老登-29;4-小路-28;5-小明-30

以上输出仔细看一下明显是不对的,这就涉及到了复杂类型对比,请看代码:

正常我们声明的类

/// <summary>
/// 学生类
/// </summary>
internal class Student
{
    /// <summary>
    /// 编号
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 年龄
    /// </summary>
    public int Age { get; set; }

}

 因为我们要对比的是引用类型,因为在对比除string引用类型外,其他引用类型的对比默认都是对比的堆里地址,所以我们要实现一个自定义的对比方案

我们需要继承一个接口 IEqualityComparer<T> 泛型接口

如下:(这里我们以年龄与名做为对比条件)

/// <summary>
/// 学生类
/// </summary>
internal class Student : IEqualityComparer<Student>
{
    /// <summary>
    /// 编号
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// 姓名
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 年龄
    /// </summary>
    public int Age { get; set; }

    /// <summary>
    /// 比较器
    /// </summary>
    /// <param name="s1">比较实体1</param>
    /// <param name="s2">比较实体2</param>
    /// <returns></returns>
    public bool Equals(Student s1, Student s2)
    {
        //验证相等条件
        if (s1.Name == s2.Name && s1.Age == s2.Age)
        {
            return true;
        }
        return false;
    }

    /// <summary>
    /// 获取唯一条件
    /// </summary>
    /// <param name="stu"></param>
    /// <returns></returns>
    public int GetHashCode(Student stu)
    {
        return (stu.Name + "|" + stu.Age).GetHashCode();
    }
}

修改了类后还有最重要的一点:就是修改比较的方法(相当于声明一个自定义的比较器给方法)

   //取比列表1里多出来的学生数据 并输出
            var ExceptData = StudentList2.Except(StudentList1,new Student());
            Console.WriteLine("差集:" + String.Join(";", ExceptData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

            //取列表1与列表2里共有的学生数据
            var IntersectData = StudentList1.Intersect(StudentList2,new Student());
            Console.WriteLine("交集:" + String.Join(";", IntersectData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

            //获取办理所有学生的数据(一个相同的学生只能一条)
            var UnionData = StudentList1.Union(StudentList2,new Student());
            Console.WriteLine("并集:"+String.Join(";", UnionData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

  差集:4-小路-28;5-小明-30

  交集:1-小明-27;2-大郭-28;3-老登-29

  并集:1-小明-27;2-大郭-28;3-老登-29;4-小路-28;5-小明-30

到这里引用类型的比较已经完成了,比较器的条件方法可以根据需求调整,如有不足之处,希望大家多多指正!!!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK