• 第7章 数组和元组


    1.区别:

    • 使用同一类型的多个对象 ==> 集合或数组
    • 使用不同类型的多个对象 ==> 元组(Tuple)

    2.简单数组:

    • 数组初始化:数组是引用类型,必须给它分配堆上的内存,应使用new运算符
      • 指定数组大小:int[] myArray = new int[4];
      • 使用初始化器赋值:int[] myArray = new int[4] {4, 7, 11, 2};
        • 简化一:使用花括号初始化数据,可不指定数组的大小                          int[] myArray = new int[] {4, 7, 11, 2};
        • 简化二:C#编译器更简化,使用花括号可以同时声明和初始化数组       int[] myArray = {4, 7, 11, 2};
    • 使用引用类型:可以声明自定义类型的数组
      • 数组元素是引用类型,就必须为每个数组元素分配内存
    //自定义Person类
    public class Person
    {
        public string FirstName {get; set;}
        public string LastName {get; set;}
        
        public override string ToString() => $"{FirstName} {LastName}";
    }    
    
    //定义Person数组
    Person[] myPersons = new Person[2];
    
    //为每个数组元素分配内存
    myPersons[0] = new Person {FirstName = "Ayrton", LastName="Senna"};
    myPersons[1] = new Person {FirstName = "Michael", LastName="Schumacher"};
      • 使用数组初始化器赋值
    Person[] myPersons2 = 
    {
         new Person {FirstName = "Ayrton", LastName="Senna"},
         new Person {FirstName = "Michael", LastName="Schumacher"}
    };

     3.多维数组:用两个或多个整数来索引

    • 二维数组:
      • 声明:需要在方括号中加上一个逗号; 
      • 初始化:
        • 应指定每一维的大小(也称为阶)==> int[,] twodim = new int[3,3];
        • 使用数组索引器
    int[,] towdim = {
                      {1, 2, 3},
                      {4, 5, 6},
                      {7, 8, 9},
                    };
    • 三维数组:在花括号中使用两个逗号声明
    int[,,] threedim = {
                      { {1, 2},  {3, 4} },
                      { {5, 6},  {7, 8} },
                      { {9, 10},  {11, 12} }
                    };
    WriteLine(threedim[0, 1, 1]);

    4. 锯齿数组:每一行都可以有不同的大小。

    • 声明时要依次放置左右括号
    • 初始化时只对第1对方框中设置数组行数。
    • 定义每行时再指定元素个数
    int[][] jagged = new int[3][];
    jagged[0] = new int[2] {1, 2};
    jagged[1] = new int[6] {3, 4, 5, 6, 7, 8};
    jagged[2] = new int[3] {9, 10, 11};

    5. Array类:用方括号声明数组是C#中使用Array类的表示法

    • Length属性或foreach语句迭代数组,使用了Array类中的GetEnumerator()方法
    • LongLength属性:数组元素个数超出整数的取值范围,使用此属性获得元素个数
    • Rank属性:获得数组的维数
    • 创建数组:
      • CreateInstance()创建是事先不知道元素类型的数组
      • SetValue()设置对应元素的值
      • GetValue()读取对应元素的值
    //创建类型为int、大小为5的一维数组
    Array intArray1 = Array.CreateInstatnce(typeof(int), 5);
    
    //强制转换成声明为int[]的数组
    int[] intArray2 = (int[])intArray1;
    
    //创建类型为Person,大小为2*3个元素的二维数组
    //且第一维基于1,第二维基于10
    int[] lengths = {2, 3};
    int[] lowerBounds = {1, 10};
    Array racers = Array.CreateInstance(typeof(Person), lengths, lowerBounds);
    •  复制数组:
      • 实现ICloneable接口,使用Clone()方法创建数组的浅表副本,即创建一个新数组。
        • 数组元素是值类型,值复制所有值。
        • 数组元素是引用类型,则不复制元素,只复制引用。
      • Array.Copy()也可以创建浅表副本,但必须传递阶数相同且有足够元素的已有数组。
    • 排序:

      • 数组使用自定义类型应实现接口有两种方式:
        • 实现IComparable接口,重写CompareTo()方法 ==> 就是在告诉大家,我实现了这个接口,所有我的实例都是可以比较的,并且比较的规则是按照我实现的IComparable中的方法CompareTo来进行的。
        • 实现IComparer接口或IComparer<T>接口,重写Compare()方法。该接口独立于要比较的类,需要两个要比较的参数。

                               注明:详细可参考 原文:https://blog.csdn.net/ios99999/article/details/77800819

      •  举例说明实现以上两种接口的自定义类型数组使用Sort()排序方法
        • 实现IComparable接口
    //自定义Person类
    public class Person : IComparable<Person>
    {
            public string FirstName { get; set; }
            public string LastName { get; set; }
    
            public override string ToString() => $"{FirstName} {LastName}";
    
            public int CompareTo(Person other)
            {
                if (other == null) throw new ArgumentNullException("other");
    
                int result = LastName.CompareTo(other.LastName);
                if (result == 0)
                {
                    result = FirstName.CompareTo(other.FirstName);
                }
    
                return result;
            }
    }
    
    
    //数组排序
    Person[] persons =  {
                    new Person { FirstName="Damon", LastName="Hill" },
                    new Person { FirstName="Niki", LastName="Lauda" },
                    new Person { FirstName="Ayrton", LastName="Senna" },
                    new Person { FirstName="Graham", LastName="Hill" }
                 };
                Array.Sort(persons);
                foreach (Person p in persons)
                {
                    WriteLine(p);
                }
    
    //排序结果
    //Damon Hill
    //Graham Hill
    //Niki Lauda
    //Ayrton Senna
        • 实现IComparer<T>接口
    //自定义PersonComparer类
    //定义了排序选项
    public enum PersonCompareType
    {
            FirstName,
            LastName
    }
    
    public class PersonComparer : IComparer<Person>
    {
            private PersonCompareType _compareType;
            
            public PersonComparer(PersonCompareType compareType)
            {
                _compareType = compareType;  //确定排序方式
            }
    
            #region IComparer<Person> Members
            // 可根据排序方式灵活进行排序
            public int Compare(Person x, Person y)
            {
                if (x == null && y == null) return 0;
                if (x == null) return 1;
                if (y == null) return -1;
    
                switch (_compareType)
                {
                    case PersonCompareType.FirstName:
                        return string.Compare(x.FirstName, y.FirstName);
                    case PersonCompareType.LastName:
                        return string.Compare(x.LastName, y.LastName);
                    default:
                        throw new ArgumentException(
                              "unexpected compare type");
                }
            }
    
            #endregion
    }
    
    //自定义类型数组排序,根据FirstName排序
    Array.Sort(persons,
                    new PersonComparer(PersonCompareType.FirstName));
    
    foreach (Person p in persons)
    {
          WriteLine(p);
    }
    
    //排序结果
    //Ayrton Senna
    //Damon Hill
    //Graham Hill
    //Niki Lauda

     6. 数组作为参数:数组可以作为参数传递给方法,也可以从方法返回

    • 数组支持协变:即可以声明一个基类参数(如object[]类型),给它传递一个派生类型(如Person[])。数组协变只能用于引用类型。
    • 部分数组:结构ArraySegment<T>表示数组的一段。可以将整个数组的某些部分传递给不同的方法。参数包括数组,偏移量和该方法使用的元素数
    //计算数组段定义的所有整数之和
    static int SumOfSegments(ArraySegment<int>[] segments)
    {
                int sum = 0;
                foreach (var segment in segments)
                {
                    for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
                    {
                        sum += segment.Array[i];
                    }
    
                }
                return sum;
    }
    
    //使用方法
    //计算数组ar1从第1个元素开始,引用3个元素;
    //计算数组ar2从第3个元素开始,引用3个元素;
    int[] ar1 = { 1, 4, 5, 11, 13, 18 };
    int[] ar2 = { 3, 4, 5, 18, 21, 27, 33 };
    var segments = new ArraySegment<int>[2]
    {
          new ArraySegment<int>(ar1, 0, 3),
          new ArraySegment<int>(ar2, 3, 3)
    };
    
    // sum = 1 + 4 + 5 + 18 + 21 + 27
    var sum = SumOfSegments(segments);
    WriteLine($"sum of all segments: {sum}");

     7. 枚举:使用foreach语句实现迭代,是由于其使用了枚举器

    •  一个类型是否支持foreach遍历,必须满足下面两个条件:
      • 这个类实现IEnumerable接口
      • 这个类有一个public的GetEnumerator的实例方法,并且返回类型中(IEnumerator)具有public 的bool MoveNext()方法和public的Current属性
    • IEnumerable接口与IEnumerator接口区别:
      • IEnumerable   可迭代的,可以说是一个声明式的接口,但没有具体如何实现迭代器(iterator),仅有可返回IEnumerator 类型的方法
      • IEnumerator    迭代器,通过实现该接口就可以作为一个迭代器(iterator),包含了具体的需要实现的方法

          注明: 详细可参考 原文:https://blog.csdn.net/i1tws/article/details/51511134?utm_source=copy

    • yield语句:便于创建枚举器,其必须声明为返回IEnumerator或IEnumerable接口
      • yield return:返回集合的一个元素
      • yield break:可停止迭代
      • 可以使用yield return语句,以不同方式迭代集合的类
      • yield return返回枚举器

    8.元组:用于合并不同类型的对象。

    • .NET Framework定义了8个泛型Tuple类和1个静态Tuple类。
    • 元组用静态Tuple类的静态Create()方法创建。

    9.结构比较:数组和元组都实现接口IStructuralEquatable和IStructuralComparable

    • IStructuralEquatable:比较两个元组或数组是否有相同的内容
    • IStructuralComparable:用于给元组或数组排序
  • 相关阅读:
    Sql 三元运算符
    连表更新
    SQL分组排序去重复
    ASP日常出错原因
    Box2D的三种Body类型
    Android获取屏幕尺寸的方法
    AndEngine之ScreenCapture
    AndEngine之IUpdateHandler,IEntityModifier
    JAVA中线程安全的类
    AndEngine引擎之SmoothCamera 平滑摄像机
  • 原文地址:https://www.cnblogs.com/zhangjbravo/p/9719378.html
Copyright © 2020-2023  润新知