using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using LinqStudy;

namespace LinqStudy.Test.LinqToObject
{
    /// <summary>
    /// 分组操作符
    /// </summary>
    public class GroupTest
    {
        /// <summary>
        /// GroupBy: 根据指定的键选择器函数对序列的元素进行分组;延迟执行。
        /// 注意:Key即分组依据,可以常用的值类型,也可以是引用类型(可以自定义比较器))
        /// </summary>
        [Fact]
        public void GroupBy_Default_Test()
        {
            List<Person> peoples=new List<Person>()
            {
                new Person(){Id=1, Name="Andy", Age=10},
                new Person(){Id=2, Name="Bab", Age=20},
                new Person(){Id=3, Name="Babs", Age=20},
                new Person(){Id=4, Name="Cara", Age=30},
                new Person(){Id=5, Name="Carlton", Age=30},
                new Person(){Id=6, Name="Cora", Age=30},
                new Person(){Id=7, Name="Dawn", Age=40},
                new Person(){Id=8, Name="Debby", Age=40},
                new Person(){Id=9, Name="Dotty", Age=40},
                new Person(){Id=10, Name="Dove", Age=40},
            };

            var group = peoples.GroupBy(p=>p.Age);
            var groupCount =  group.Count();

            Assert.Equal(4,groupCount);
        }

        /// <summary>
        /// 延迟执行
        /// </summary>
        [Fact]
        public void GroupBy_Delay_Test()
        {
            List<Person> peoples=new List<Person>()
            {
                new Person(){Id=1, Name="Andy", Age=10},
                new Person(){Id=2, Name="Bab", Age=20},
                new Person(){Id=3, Name="Babs", Age=20},
                new Person(){Id=4, Name="Cara", Age=30},
                new Person(){Id=5, Name="Carlton", Age=30},
                new Person(){Id=6, Name="Cora", Age=30},
            };

            var group = peoples.GroupBy(p=>p.Age);

            //改变数据源
            List<Person> peoples2=new List<Person>()
            {
                new Person(){Id=7, Name="Dawn", Age=40},
                new Person(){Id=8, Name="Debby", Age=40},
                new Person(){Id=9, Name="Dotty", Age=40},
                new Person(){Id=10, Name="Dove", Age=40},
            };
            peoples.AddRange(peoples2);

            //受数据源变化的影响,说明是延迟执行。
            var groupCount =  group.Count();

            Assert.Equal(4,groupCount);
        }
    
        /// <summary>
        ///  重载2:keySelector, comparer
        ///  key:是引用类型,使用自定义比较器
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_comparer_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=2, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=3, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=4, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},

            };

            var group = peoples.GroupBy
            (
                p=>p.Hometown,
                new HometownEqualityComparer()
            );

            var actual=group.First().Select(q=>q.Name).ToList();
            var expected=new List<string>(){"河南周口人","俺河南周口哩"};

            Assert.Equal(expected,actual);
        }

        /// <summary>
        ///  重载3:keySelector, elementSelector
        ///  key:是引用类型,使用自定义比较器
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_elementSelector_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=1, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=2, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=3, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},

            };

            var group = peoples.GroupBy
            (
                p=>p.Id,
                t=>t.Name
            )
            .ToList();

            var actual=group[2].FirstOrDefault();
            var expected="上海松江人";

            Assert.Equal(expected,actual);
        }
        /// <summary>
        /// 重载4:keySelector elementSelector comparer
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_elementSelector_comparer_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=2, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=3, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=4, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},

            };

            var group = peoples.GroupBy
            (
                p=>p.Hometown,
                t=>t.Name,
                new HometownEqualityComparer()
            )
            .ToList();

            var actual=group[2].FirstOrDefault();
            var expected="上海松江人";

            Assert.Equal(expected, actual);
        }
        
        /// <summary>
        ///  重载5:keySelector resultSelector
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_resultSelector_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=1, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=3, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=4, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},

            };

            var group = peoples.GroupBy
            (
                p=>p.Id, 
                (key,teacher) => teacher.Select(t=>t.Name)
            )
            .ToList();

            var lastGroupItem=group[2].FirstOrDefault();
            var expected="上海松江人";

            Assert.Equal(expected,lastGroupItem);
        }

        /// <summary>
        ///  重载6:keySelector resultSelector
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_resultSelector_comparer_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=1, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=3, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=4, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},
            };

            var group = peoples.GroupBy
            (
                p=>p.Hometown, 
                (key,teacher) => teacher.Select(t=>t.Name),
                new HometownEqualityComparer()
            )
            .ToList();

            var lastItem=group[2].FirstOrDefault();
            var expected="上海松江人";

            Assert.Equal(expected, lastItem);
        }

        /// <summary>
        ///  重载7:keySelector elementSelector resultSelector
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_elementSelector_resultSelector_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=1, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=3, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=4, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},
            };

            var group = peoples.GroupBy
            (
                p=>p.Hometown.Province+p.Hometown.City,
                (teacher)=> new {Id= teacher.Id,name=teacher.Name, Province=teacher.Hometown.Province},
                (key, result) => result.Select(q=>q.Province)
            )
            .ToList();

            var lastItem=group[2].FirstOrDefault();
            var expected="上海";

            Assert.Equal(expected, lastItem);
        }

        /// <summary>
        ///  重载8:keySelector elementSelector resultSelector
        /// </summary>
        [Fact]
        public void GroupBy_keySelector_elementSelector_resultSelector_comparer_Test()
        {
            List<Teacher> peoples=new List<Teacher>()
            {
                new Teacher(){Id=1, Name="河南周口人", Hometown=new Hometown(){Province="河南", City="周口"}},
                new Teacher(){Id=1, Name="俺河南周口哩", Hometown=new Hometown(){Province="河南",City="周口"}},
                new Teacher(){Id=3, Name="上海宝山人", Hometown=new Hometown(){Province="上海",City="宝山"}},
                new Teacher(){Id=4, Name="上海松江人", Hometown=new Hometown(){Province="上海",City="松江"}},
            };

            var group = peoples.GroupBy
            (
                p=>p.Hometown,
                (teacher)=> new {Id= teacher.Id,name=teacher.Name, Province=teacher.Hometown.Province},
                (key, result) => result.Select(q=>q.Province),
                new HometownEqualityComparer()

            )
            .ToList();

            var lastItem=group[2].FirstOrDefault();
            var expected="上海";

            Assert.Equal(expected, lastItem);
        }
    }
}