• 对像集合使用过程中的一些总结


    1. 设计可比较大小的对像   

    2. 针对数组元素的查询与转换   

    3. 针对对像集合的标准查询   

    1.设计可比较大小的对像

    众所周知,数值型变量之间可以直接比较大小

     如:

     Int i=100;

     Int j=100;

     Console.Writeline(i>j); //输出false

     之所以可以比较两个整型变量的大小,是因为在数学上两个整数之间谁大谁小有明确定义,比较两个整形变量时,实际上比较的是这两个整形变量所保存数值的大小。

     然而同将同样的方法应用于引用类型的变量 ,问题来了,代码无法通过编译

     Object o1=new object();

     Object o2=new object();

     Console.WriteLine(o1 > o2);

     上述代码之所以不能通过编译,是因为两个变量引用了两个object类形的对像,而默认情况下两个object类型对像谁大谁小是未定义的。

    但在某此具体的场景下,确定两个对像的大小是有意义的

    比如判断两个圆的大小,半径相等的圆就可以认为是相等的圆,半径越大的圆也就越大,

    如果用Circle类来表示一个圆,上述问题就转换为Circle对像的大小比较问题。

    默认情况下,.Net Formework显示什么

    Circle obj1 = new Circle() { Radio = 100 };

    Circle obj2 = new Circle() { Radio = 100 };

    Console.WriteLine(obj1 == obj2); //false

    Console.WriteLine(obj1.Equals(obj2)); //false

    虽然两个圆的半径是相等的,希望两个对像比较的结果是true,但由于对像变量obj1与obj2引用的是两个不同的对像,所以==返回false,equals也是比较两个对像是否引用同一对像,所以也返回false。

    修改代码,实现IComparable接口,自定义一个CompareTo方法,用于比较大小

        class Circle:IComparable

        {

            public double Radio = 0; //半径

            public CircleCenter center; //圆心

            public int CompareTo(object obj)

            {

                double ret = Math.Abs((obj as Circle).Radio - this.Radio);

                if (ret==0)

                    return 0;//相等

                if ((obj as Circle).Radio < this.Radio)

                {

                    return 1;//大

                }

                return -1; //小

            }

        }

    有许多情况,可能只需要知道两个对像是否相等,而不需要知道这两个对像谁大谁小,这时可以重写object类的equals方法

        public override bool Equals(object obj)

            {

                if (this.CompareTo(obj) == 0)

                {

                    return true;

                }

                return false;

            }

    重写或重载object.equals需满足三点

    1.自反性:即自身与自身相等。a.Equals(a) 返回true

    2.对称性:若a与b相等,则b与a也相等,这就是说a.Equals(b)与b.Equals(a)的值一次是相等的

    3.传递性:若a与b相等,b与c相等,则a与c相等。这就是说如果a.Equals(b)和b.Equals(c)都为true,则a.Equals(c)的值也为true

    重写了equals方法,马上就可以重载==运算符,若一个对像重载了==运算符,也必须重载!=运算符,这是一个编程的基本原则,

    完整代码见下方 

     class Program
        {
            static void Main(string[] args)
            {
                Circle obj1 = new Circle() { Radio = 100 };
                Circle obj2 = new Circle() { Radio = 100 };
                Console.WriteLine(obj1.Equals(obj2)); //true
                Console.WriteLine(obj1.CompareTo(obj2));//0
                Console.WriteLine(obj1 != obj2); //false

                Circle[] circles = new Circle[4]{new Circle{Radio=10},
                                                  new Circle{Radio=20},
                                                  new Circle{Radio=15},
                                                  new Circle{Radio=18}};
                Array.Sort(circles);
                foreach (Circle c in circles)
                {
                    Console.WriteLine(c.Radio);
                }
                    Console.ReadKey();
            }

        }
        class Circle:IComparable
        {
            public double Radio = 0; //半径
           // public CircleCenter center; //圆心
            public int CompareTo(object obj)
            {
                double ret = Math.Abs((obj as Circle).Radio - this.Radio);
                if (ret==0)
                    return 0;//相等
                if ((obj as Circle).Radio < this.Radio)
                {
                    return 1;//大
                }
                return -1; //小
            }
            //重写Equals方法
            public override bool Equals(object obj)
            {
                if (this.CompareTo(obj) == 0)
                {
                    return true;
                }
                return false;
            }
            //覆盖Object类的GetHashCode方法
            public override int GetHashCode()
            {
                //整数部分与小数点后3位相同的对象生成相同的哈希值
                return (int)(Radio * 1000);
            }
            //重载相关运算符
            public static bool operator ==(Circle obj1, Circle obj2)
            {
                return obj1.Equals(obj2);
            }
            public static bool operator !=(Circle obj1, Circle obj2)
            {
                return !obj1.Equals(obj2);
            }
            public static bool operator >(Circle obj1, Circle obj2)
            {
                return obj1.CompareTo(obj2)==1;
            }
            public static bool operator <(Circle obj1, Circle obj2)
            {
                return obj1.CompareTo(obj2) == -1;
            }
        }

    2.针对数组元素的查询与转换

    在某些情况下可能会需要将数组中的元素转换为另一个类型,这个工作可以通过调用数组基类Array的ConvertAll方法实现:

        class Program
        {
            static void Main(string[] args)
            {
                int[] intArr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
                double[] doublearr = Array.ConvertAll<int, double>(intArr, IntToDouble);
                foreach (double d in doublearr)
                {
                    Console.WriteLine(d);
                }
                Console.ReadKey();
            }
            static Converter<int, double> IntToDouble = delegate(int value)
            {
                return (double)value;
            };

        }

    当需要循环迭代数组中的所有元素,并且对这些元素都进行同样的处理工作时,可以调用数组基类的Array的Foreach<T>方法达到目的

        class Program
        {
            static void Main(string[] args)
            {
                //源数组
                int[] SourceArr = new int[] { 0, 1, 2, 3, 4, 5, 6 };
                //目标数组
                int[] TargetArr = new int[SourceArr.Length];
                int index=0;
                Action<int> DoubleArr = delegate(int element)
                {
                    TargetArr[index++] = element * 2;
                };
                //循环源数组,把数据存入目标数组
                Array.ForEach<int>(SourceArr, DoubleArr);
                Array.ForEach<int>(TargetArr,element => { Console.WriteLine(element); });
                Console.ReadKey();
            }
        }

    实际开发中数据排序很常见,数组基类Array直接就内置了相应的排序功能,比如选择择排序,冒泡排序

    Sort方法是最简单的:例

     class Program
        {
            static void Main(string[] args)
            {
                int[] IntArr = new int[10];
                Random ran = new Random();
                for (int i = 0; i < IntArr.Length; i++)
                {
                    IntArr[i] = ran.Next(1, 100);
                }
                Array.Sort(IntArr);
                Console.ReadKey();
            }
        }

    当调用此方法时,要求数组中的元素要实现System.IComparable接口,否则此方法会抛出InvalidOperationException异常,如果数组中元素没有实现Icomparable接口 ,可以提供一个对像比较器完成排序,或者更简单些,不需要定义一个对像比较器,直接给Sort提供一个可以比较两对像大小的方法

        class Program
        {
            static void Main(string[] args)
            {
                 Random ran = new Random();
                 MyClass[] obj = new MyClass[10];
                for (int i = 0; i < obj.Length; i++)
                {
                    obj[i] = new MyClass { value = ran.Next(1, 100) };
                }

               //定义一个委托,用于比较两个对像大小,当x>y时,返回一个正数,当x=y时,返回0,当x<y时返回负数
                Comparison<MyClass> WhoIsGreater = delegate(MyClass x, MyClass y)
                {
                    if (x.value > y.value)
                        return 1;
                    else if (x.value == y.value)
                        return 0;
                    else
                        return -1;
                };

                //未排序前输出
                Array.ForEach(obj, element => { Console.Write(element.value + ","); });
                //排序

                Array.Sort(obj,WhoIsGreater);
                Console.WriteLine("");

               //排序后输出
                Array.ForEach(obj, element => { Console.Write(element.value + ","); });
                Console.ReadKey();
            }
        }

    Sort方法提供了多个形式的重载,有一个重载可以实现两个数组的联动,假设有两个一样长度的数组(分别叫keys和Itmes),这两个数组的元素是一一对应的,这就是说,keys数组的第一个元素对应Items数据中的第一个元素,对Keys数组中的元素进行排序同时也会更改Items中的元素位置,以维护这两个数据元素间的连动关系。示例中字符串数组存放代表一周的七个英文单词,而int数组则保存1-7个整数,并且与字符串数组的星期单词是连动的

        class Program
        {
            static void Main(string[] args)
            {
                int[] Keys = new int[] { 7, 2, 3, 4, 1, 5, 6 };
                string[] Items = new string[] { "Sunday", "Wednesssday", "Thursday", "Tuesday", "Monday", "Friday", "Saturday" };  

                //对keys排序,对应的items也会跟着变

                Array.Sort<int,string>(Keys,Items);
                Array.ForEach(Keys, element => { Console.Write(element + ","); });
                Console.WriteLine("");
                Array.ForEach(Items, element => { Console.Write(element + ","); });
                Console.ReadKey();
            }
        }

    有时可能希望保存在数组中的元素都满足特定的要求,数组基类Array提供了相应的静态方法完成这一工作

    TrueForAll<T>方法所有的条件是否都满足,只要有一个不满足就返回false,代码示例如下:

        class Program
        {
            static void Main(string[] args)
            {
                Predicate<int> match = delegate(int value)
                {
                    return value % 2 == 0;
                };
                int[] IntArr=new int[]{0,1,2,3,4,5,6,7,8,9};

                //判断数组元素是否都为偶数,true全部是偶数,如果有一个不是偶数即返回false
                bool IsAllEven = Array.TrueForAll(IntArr, match);

          }
        }

    判断数组中是否存在满足某个特定元素可以用Exists<T>,代码示例如下:

        class Program
        {
            static void Main(string[] args)
            {
                int[] IntArr=new int[]{0,1,2,3,4,5,6,7,8,9};
                Predicate<int> ExistEventNumber = delegate(int value)
                {
                    if (value > 8)
                        return true;
                    return false;
                };
                bool IsExists = Array.Exists(IntArr, ExistEventNumber);
            }
        }

    TrueForAll<T>跟Exists<T>区别在于:前者全部满足指定条件才返回true,后者只要有一个满足即返回true

    数组基类Array还提供了一堆的方法用于查找元素

    Find<T>:从数组开头查找匹配元素,FindLast<T>从数组结尾开始向前查找匹配元素

    FindAll<T>:查找数据中满足特定条件的所有元素

    FindIndex<T>:查找数组中满足特定条件的元素所在的位置(索引)

    3. 对像集合的标准查询

    .Net基类库中大多数集合都实现了IEnumerable<T>接口,从.Net3.5开始,.Net基类库中提供了一组针对IEnumerable<T>接口的扩展方法,为各种对像集合提供各种标准查询服务,这些扩展方法返回一个对像集合,可以使用foreach语句逐个访问这些对像,或者将其用作数据绑定控件的数据源,这组扩展方法功能强大,使用灵活,实际构成了LINQ技术大厦的地基

    筛选:是指从对像集合中选出那些满足特定条件的对像,可通过where扩展方法实现,下图程序是从指定路径中获取包含指定字符的文件名

    完整代码如下:

    class FileBroseHelper

        {

            /// <summary>

            /// 取指定文件夹中的文件

            /// </summary>

            /// <param name="foldername"></param>

            /// <returns></returns>

            public static List<FileInfo> GetAllFileInFolder(string foldername)

            {

                try

                {

                    List<FileInfo> files = null;

                    if (!Directory.Exists(foldername))

                    {

                        return null;

                    }

                    DirectoryInfo d = new DirectoryInfo(foldername);

                    files = d.GetFiles().ToList();

                    return files;

                }

                catch (Exception ex)

                {

                    throw (ex);

                }

            }

            /// <summary>
            /// 将文件显示到listbox中
            /// </summary>
            /// <param name="file"></param>
            /// <param name="list"></param>

            public static void ShowFileListInListBox(IEnumerable<FileInfo> file, System.Windows.Forms.ListBox list)

            {

                list.Items.Clear();

                foreach (FileInfo f in file)

                {

                    list.Items.Add(f);

                }

            }

        }

    按钮事件如下:

      private void btnClick_Click(object sender, EventArgs e)
            {
                if (txtFolderNam.Text.Trim().Length == 0)
                {
                    return;
                }
                if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
                {
                    //获取选择的路径
                    string foldername = folderBrowserDialog1.SelectedPath;
                    labTitle.Text = foldername;
                    //取该路径下所有文件
                    List<FileInfo> files = FileBroseHelper.GetAllFileInFolder(foldername);
                    IEnumerable<FileInfo> ret = files.Where<FileInfo>(file =>file.Name.IndexOf(txtFolderNam.Text)!=-1);
                    //把筛选出来的文件名显示在listbox中
                    FileBroseHelper.ShowFileListInListBox(ret, listBox1);
                }
            }

    上述代码中Lambda表达式给Where扩展方法赋值,用到是的FilInfo是System.IO命名空间中的类,封装了文件的基本信息和常用操作。

    投影:指把某对像集合中对像的部分属性抽取出来

    数据转换:指将某对像集合中感兴趣的对像(或抽取它的部分字段/属性)转换为另一种类型的对像

    代码见下方:

        class Program
        {
            static void Main(string[] args)
            {
                //转换为不同类型的集合
                IEnumerable<string> filelist = Directory.GetFiles("c:\\", "*.*");
                IEnumerable<FileInfo> files = filelist.Select(file => new FileInfo(file));
                foreach (FileInfo f in files)
                {
                    Console.WriteLine(f);
                }
                //返回一个匿名对像的集合
              var items =filelist.Select(file=>{
                                                FileInfo f=new FileInfo(file);
                                                return new { FileName = f.Name, Size = f.Length };
                                               });
              foreach (var i in items)
              {
                  Console.WriteLine(i.FileName + "," + i.Size);
              }
                Console.ReadKey();
            }
        }

    排序:使用扩展方法OrderBy(升序),OrderByDescending(降序)进行排序

    代码见下方:

        class Program
        {
            static void Main(string[] args)
            {
                Pet[] pets = new Pet[]{new Pet{Name="Tiger",Age=22},
                new Pet{Name="Lion",Age=17},
                new Pet{Name="rabbit",Age=18}};
                IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
                foreach (var q in query)
                {
                    Console.WriteLine(q.Age);
                }
                Console.ReadKey();

            }
        }
        class Pet
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

    数据连接:指根据某个对像的属性将两个数据集合的对像连接起来,得到一个新的集合

        class Program
        {
            static void Main(string[] args)
            {
                A[] a = new A[10];
                B[] b = new B[10];
                for (int i = 0; i <10; i++)
                {
                    a[i] = new A { AID = i, AName = "AName" + i.ToString() };
                    b[i] = new B { BID = i, BName = "BName" + i.ToString() };
                }
                var result = a.Join(b, aobj => aobj.AID, bobj => bobj.BID, (aobj, bobj) => new { aobj.AID, aobj.AName, bobj.BName });
                foreach (var elem in result)
                {
                    Console.WriteLine("{0},{1},{2}", elem.AID, elem.AName, elem.BName);
                }
                Console.ReadKey();
            }
        }
        class A
        {
            public int AID;
            public string AName;
        }
        class B
        {
            public int BID;
            public string BName;
        }

    集合运算:常用的集合运算包括求交集,并集,差集等,.Net基类库提供了一组扩展方法来完成标准集合运算,例如union,contact,sum,intersect等

    示例代码如下:

     class Program
        {
            static void Main(string[] args)
            {
                //创建一个多态对象集合
                IEnumerable<object> stuff = new object[] { new object(), 1, 3, 5, 7, 9, "\"thing\"", Guid.NewGuid() };
                //输出数组的内容
                Print("Stuff集合的内容: {0}", stuff);

                //偶数集合
                IEnumerable<int> even = new int[] { 0, 2, 4, 6, 8 };
                Print("偶数集合的内容: {0}", even);

                //从多态集合stuff中筛选中整数元素(全部为奇数)组成一个新集合
                IEnumerable<int> odd = stuff.OfType<int>();

                Print("奇数集合的内容: {0}", odd);

                //求两个集合的并集
                IEnumerable<int> numbers = even.Union(odd);
                Print("奇数与偶数集合的并集,成为一个整数集合: {0}", numbers);

                Print("整数集合与偶数集合的并集: {0}", numbers.Union(even));

                Print("整数集合与奇数集合相连接: {0}", numbers.Concat(odd));

                Print("整数集合与偶数集合的交集: {0}", numbers.Intersect(even));

                Print("整数集合与奇数集合连接,再删除重复值: {0}", numbers.Concat(odd).Distinct());


                if (!numbers.SequenceEqual(numbers.Concat(odd).Distinct()))
                {
                    throw new Exception("Unexpectedly unequal");
                }
                else
                {

                    Print("反转整数集合: {0}", numbers.Reverse());

                    Print("求整数集合的平均值: {0}", numbers.Average());
                    Print("求整数集合的总和: {0}", numbers.Sum());
                    Print("求整数集合的最大值: {0}", numbers.Max());
                    Print("求整数集合的最小值: {0}", numbers.Min());
                }

                Console.ReadKey();
            }

            private static void Print<T>(string format, IEnumerable<T> items)
            {
                StringBuilder text = new StringBuilder();

                foreach (T item in items.Take(items.Count() - 1))
                {
                    text.Append(item + ", ");
                }


                text.Append(items.Last());
                Console.WriteLine(format, text);
            }

            private static void Print<T>(string format, T item)
            {
                Console.WriteLine(format, item);
            }
        }

  • 相关阅读:
    实例属性 类属性 实例域 类域
    研究数据集
    static 静态域 类域 静态方法 工厂方法 he use of the static keyword to create fields and methods that belong to the class, rather than to an instance of the class 非访问修饰符
    accessor mothod mutator mothod 更改器方法 访问器方法 类的方法可以访问类的任何一个对象的私有域!
    上钻 下钻 切片 转轴 降采样
    识别会话
    Performance Tuning Using Linux Process Management Commands
    Secure Hash Algorithm 3
    grouped differently across partitions
    spark 划分stage Wide vs Narrow Dependencies 窄依赖 宽依赖 解析 作业 job stage 阶段 RDD有向无环图拆分 任务 Task 网络传输和计算开销 任务集 taskset
  • 原文地址:https://www.cnblogs.com/75115926/p/3062290.html
Copyright © 2020-2023  润新知