一、数组的基础知识

1、数组有什么用?

如果需要同一个类型的多个对象,就可以使用数组。数组是一种数组结构,它可以包含同一个类型的多个元素.

2、数组的初始化方式

第一种:先声明后赋值

  1. int[] array = new int[];
  2. array[] = ;
  3. array[] = ;
  4. array[] = ;

第二种:使用数组初始化器对数组进行赋值。注:数组初始化器只能在声明数组变量时使用,不能在声明数组变量之后使用.

  1. //正确
  2. int[] array = new int[] { , , };
  3.  
  4. //错误
  5. int[] array1=new int[];
  6. array1 = { , , };

关于第二种方法,C#提供了两个方式的"语法糖";

  1. //语法糖一
  2. int[] array = new int[] { , , };
  3.  
  4. //语法糖二
  5. int[] array={,,};

3、引用类型数组

C#除了能声明和处理预定义类型的数组之外,还能声明自定义类型的数组。

  1. public class Person
  2. {
  3. public string FirstName{get;set;}
  4. public string LastName{get;set;}
  5. }
  6. Person[] person=new Person[];

预定义类型数组能干的事,自定义类型数组也都能干.

4、多维数组

二维数组的声明方式:

  1. int[,] twodim = new int[, ];
  2. twodim[, ] = ;
  3. twodim[, ] = ;
  4. twodim[, ] = ;
  5. twodim[, ] = ;
  6. twodim[, ] = ;
  7. twodim[, ] = ;
  8. twodim[, ] = ;
  9. twodim[, ] = ;
  10. twodim[, ] = ;

语法糖:

  1. int[,] twodim ={
  2. {,,},
  3. {,,},
  4. {,,}
  5. };

三维数组:

因为日常开发中不常用到,所以就不解释了.百度百科

5、锯齿数组

锯齿数组是一个特殊的二维数组,常规的二维数组都是矩形,大部分都是各行的个数都相同,而锯齿数组则不一样,锯齿数组的第一行有3个,第二行可能有6个,第三行可能有7个......以此类推.锯齿数组的声明方式如下:

  1. int[][] jagged = new int[][];
  2. jagged[]=new int[]{,};
  3. jagged[] = new int[] { , , , , , };
  4. jagged[] = new int[] { , , , };
  5. for (int row = ; row < jagged.Length; row++)
  6. {
  7. for (int element = ; element < jagged[row].Length; element++)
  8. {
  9. Console.WriteLine("第{0}行,第{1}个,值为{2}", row, element, jagged[row][element]);
  10. }
  11. }
  12. Console.ReadKey();

二、Array类

使用方括号创建数组其实是用Array的表示法,当我们使用方括号创建了一个数组时,C#编译器会创建一个派生自抽象基类的Array的新类.这样使用方括号创建的数组对象就可以使用Array类为每个数组定义的方法和属性了.如:可以使用foreach迭代数组,其实就是使用了Array类中GetEnumerator()方法.

1、使用静态方法CreateInstance创建一维数组,并使用SetValue对数组进行赋值,使用GetValue获取数组中的值

  1. Array array=Array.CreateInstance(typeof(int), );
  2. for (int i = ; i < array.Length; i++)
  3. {
  4. array.SetValue(i + , i);
  5. }
  6. for (int i = ; i < array.Length; i++)
  7. {
  8. Console.WriteLine(array.GetValue(i));
  9. }

2、使用静态方法CreateInstance创建二维数组,并使用SetValue对数组进行赋值,使用GetValue获取数组中的值

注:通过GetUpperBound获取维度的上限,通过GetLowerBound获取维度的下限

  1. Array array=Array.CreateInstance(typeof(int),,);
  2. int value = ;
  3. for(int row=;row<array.GetUpperBound();row++)
  4. for (int element = ; element < array.GetUpperBound(); element++)
  5. {
  6. array.SetValue(value, row, element);
  7. value++;
  8. }
  9. for (int row = ; row < array.GetUpperBound(); row++)
  10. for (int element = ; element < array.GetUpperBound(); element++)
  11. {
  12. if (element == array.GetUpperBound() - )
  13. {
  14. Console.WriteLine();
  15. }
  16. else
  17. {
  18. string nbsp = " ";
  19. string res = array.GetValue(row, element).ToString().PadLeft(, '');
  20. res=element == array.GetUpperBound() - ? res : res + nbsp;
  21. Console.Write(res);
    }
  22. }
  23.  
  24. }
  25. Console.ReadKey();

3、使用静态方法CreateInstance创建三维数组,并使用SetValue对数组进行赋值,使用GetValue获取数组中的值

注:通过GetUpperBound获取维度的上限,通过GetLowerBound获取维度的下限

  1. Array array = Array.CreateInstance(typeof(int), , , );
  2. int value = ;
  3. for (int x = ; x < array.GetUpperBound(); x++)
  4. for (int y = ; y < array.GetUpperBound(); y++)
  5. for (int z = ; z < array.GetUpperBound(); z++)
  6. {
  7. array.SetValue(value, x, y, z);
  8. value++;
  9. }
  10.  
  11. for (int x = ; x < array.GetUpperBound(); x++)
  12. for (int y = ; y < array.GetUpperBound(); y++)
  13. for (int z = ; z < array.GetUpperBound(); z++)
  14. {
  15. Console.WriteLine("x坐标:{0},y坐标:{1},z坐标:{2},值为:{3}", x, y, z, array.GetValue(x, y, z));
  16. }
  17. Console.ReadKey();

部分截图

4、复制数组

数组是引用类型,所以将一个数组变量赋值给另一个数组变量,就会得到两个引用同一个数组的变量,所以通过任何一个引用修改数组的值,两个引用都会受影响.

  1. int[] array = { , , };
  2. int[] otherArray = array;
  3. array[] = ;
  4. Console.WriteLine(otherArray[]);
  5. otherArray[] = ;
  6. Console.WriteLine(array[]);

所以单纯的通过复制引用的方法,并不能实现数组的复制,必须通过其它的方法来复制数组,C#提供了两种复制数组的方式:

第一种:C#中的数组都实现了ICloneable接口,所以通该接口中定义的Clone()方法就能实现数组的浅拷贝(什么是浅拷贝,后续会介绍).

  1. int[] array = { , , };
  2. int[] arrayClone = (int[])array.Clone();
  3. array[]=;
  4. Console.WriteLine(object.ReferenceEquals(array,arrayClone));//False 说明使用Clone()方法拷贝后的数组是重新创建的
  5. Console.WriteLine(arrayClone[] +"..." + array[]);

第二种:Array.Copy()

复制一维数组:

  1. int[] array = { , , };
  2. int[] arrayCopy=new int[array.Length];
  3. Array.Copy(array, arrayCopy,array.Length);//最后一个参数为要复制的个数
  4. for (int i = ; i < arrayCopy.Length; i++)
  5. {
  6. Console.WriteLine(arrayCopy[i]);
  7. }

复制二维数组:

  1. int[,] array = { {,,},{,,},{,,} };
  2. int[,] arrayCopy = new int[array.GetUpperBound()+, array.GetUpperBound()+];
  3. Array.Copy(array,arrayCopy,array.Length);//最后一个参数为要复制的个数
  4. for (int i = ; i <= arrayCopy.GetUpperBound(); i++)
  5. for (int x = ; x <= arrayCopy.GetUpperBound(); x++)
  6. Console.WriteLine("第{0}行,第{1}个,值为:{2}",i,x,arrayCopy.GetValue(i,x));
  7. Console.ReadKey();

第三种:CopyTo

  1. int[] array = { , , };
  2. int[] arrayCopyTo=new int[array.Length];
  3. array.CopyTo(arrayCopyTo,);
  4. Console.WriteLine(object.ReferenceEquals(array,arrayCopyTo));
  5. for (int i = ; i < arrayCopyTo.Length; i++)
  6. {
  7. Console.WriteLine(arrayCopyTo[i]);
  8. }

Clone()和Array.Copy()的区别主要是:Clone()方法直接复制整个目标数组,然后进行拆箱就可以使用,但是Array.Copy()方法则必须要提供相同维数的数组和需要复制的元素个数,才能复制成功。

Clone()和CopyTo()方法的区别主要是:CopyTo()需要提供一个开始复制的起始索引.

什么是浅拷贝和深拷贝?

当数组中存在引用类型的元素时,这个时候使用Clone()或者Array.Copy()或者CopyTo()方法进行的数组复制都是浅拷贝,只会复制引用类型的索引,这意味这当修改原数组中的引用类型的值时,拷贝后的数组中的引用类型的值也会做相应的改变,所以使用上述方法进行的数组拷贝都将是浅拷贝.所以如果你想要创建包含引用类型的数组的深层副本,就必须迭代数组并创建新对象.这个过程也叫深拷贝.

  1. Person p = new Person("张三", );
  2. object[] array = { , , , p, };
  3. object[] arrayClone = (object[])array.Clone();
  4. p.Name = "李四";
  5. Console.WriteLine((arrayClone[] as Person).Name);
  6.  
  7. class Person
  8. {
  9. public Person()
  10. { }
  11. public Person(string name,int age)
  12. {
  13. this.Name = name;
  14. this.Age = age;
  15. }
  16. public string Name { get; set; }
  17. public int Age { get; set; }
  18. }

说明Clone()方法确实是浅拷贝,至于Array.Copy()和CopyTo()也是浅拷贝-这两个请自行验证.

5、数组排序

(1)、简单类型数组排序(简单类型如:System.String、System.Int、System.Double、System.Float等)

Array类使用QuickSort算法对数组中的元素进行排序。主要通过Array.Sort()方法来进行排序,Sort()方法需要数组中元素都实现IComparable接口,因为简单类型(如System.String和System.Int32)实现了IComparable接口,所以可以对包含这些类型的元素进行排序.如下代码,就是简单的对string类型数组和int数组进行排序,代码如下:

  1. string[] player ={
  2. "LeBron James",
  3. "Stepen Curry",
  4. "Kevin Durrent",
  5. };
  6. Array.Sort<string>(player);
  7. foreach (var item in player)
  8. {
  9. Console.WriteLine(item);
  10. }
  11.  
  12. int[] nums = { , , , , , , , };
  13. Array.Sort<int>(nums);
  14. foreach (var item in nums)
  15. {
  16. Console.WriteLine(item);
  17. }

(2)、自定义类型利用Sort()方法排序

a、通过自定义类型实现IComparable接口,来实现自定义类型数组的排序。注:该方法适用于要进行的自定义实体类(本例中为Person类)可修改的情况下!

如果数组的类型为自定义类型,且需要使用Sort()对该书组进行排序,那么当前自定义类就必须实现IComparable接口,该接口只定义了一个方法CompareTo(),如果要比较的对象相等,该方法就返回0,如果该实例应排在参数的前面,该方法返回-1,如果该实例应排在参数的后面,该方法返回1.CompareTo方法的返回值规则和string.Compare()方法相同,如下图:

如上图示,当前实例应该排在参数的前面,所以result的值应为-1

ok,说明上面的结论正确(这里对象相等和当前实例排在参数后面的情况自行证明).那么CompareTo()方法的返回也应该这么写,代码如下:

  1. static void Main(string[] args)
  2. {
  3. Person[] people =
  4. {
  5. new Person{FirstName="Damon",LastName="Hill"},
  6. new Person{FirstName="Niki",LastName="Lauda"},
  7. new Person{FirstName="Ayrton",LastName="Senna"}
  8.  
  9. };
  10. Array.Sort<Person>(people);
  11. foreach (var item in people)
  12. {
  13. if (item == null)
  14. Console.WriteLine("null");
  15. else
  16. Console.WriteLine(item.ToString());
  17. }
  18. Console.ReadKey();
  19.  
  20. }
  21. class Person:IComparable<Person>
  22. {
  23. public string FirstName { get; set; }
  24. public string LastName { get; set; }
  25.  
  26. public int CompareTo(Person other)
  27. {
  28. if (other == null) return ;
  29. int result = string.Compare(this.FirstName, other.FirstName);
  30. if (result == )//如果FirstName相等,则判断LastName
  31. result = string.Compare(this.LastName, this.LastName);
  32. return result;
  33. }
  34.  
  35. public override string ToString()
  36. {
  37. return this.FirstName + " " + this.LastName;
  38. }
  39. }

b、当要进行排序的自定义类型不能进行修改的时候,就采用b方法

  1. static void Main(string[] args)
  2. {
  3. Person[] people =
  4. {
  5. new Person{FirstName="Damon",LastName="Hill"},
  6. new Person{FirstName="Damon",LastName="Green"},
  7. new Person{FirstName="Niki",LastName="Lauda"},
  8. new Person{FirstName="Ayrton",LastName="Senna"}
  9.  
  10. };
  11. Array.Sort<Person>(people,new PersonCompare(PersonCompareType.LaseName));
  12. foreach (var item in people)
  13. {
  14. if (item == null)
  15. Console.WriteLine("null");
  16. else
  17. Console.WriteLine(item.ToString());
  18. }
  19. Console.ReadKey();
  20.  
  21. }
  22. public enum PersonCompareType
  23. {
  24. FirstName=,
  25. LaseName=
  26. }
  27. public class PersonCompare : IComparer<Person>
  28. {
  29. private PersonCompareType _compareType;
  30. public PersonCompare(PersonCompareType compareType)
  31. {
  32. this._compareType = compareType;
  33. }
  34. public int Compare(Person x, Person y)
  35. {
  36. if (x == null && y == null)
  37. return ;
  38. if (x == null) return ;
  39. if (y == null) return -;
  40. switch (this._compareType)
  41. {
  42. case PersonCompareType.FirstName: return string.Compare(x.FirstName, y.FirstName);
  43. case PersonCompareType.LaseName: return string.Compare(x.LastName, y.LastName);
  44. default: throw new ArgumentException("unexcepted compare type");
  45. }
  46. }
  47.  
  48. }
  49. public class Person
  50. {
  51. public string FirstName { get; set; }
  52. public string LastName { get; set; }
  53. public override string ToString()
  54. {
  55. return this.FirstName + " " + this.LastName;
  56. }
  57. }

c、传递一个比较两个对象大小的委托delegate int Comparison<in T>(T x, T y),该方法最为简洁,即不污染要进行排序的对象,又能使用lambda表达式

  1. static void Main(string[] args)
  2. {
  3. Person[] people =
  4. {
  5. new Person{FirstName="Damon",LastName="Hill"},
  6. new Person{FirstName="Damon",LastName="Green"},
  7. new Person{FirstName="Niki",LastName="Lauda"},
  8. new Person{FirstName="Ayrton",LastName="Senna"}
  9.  
  10. };
  11. Comparison<Person> compare = (Person x, Person y) =>
  12. {
  13. if (x == null && y == null)
  14. return ;
  15. if (x == null) return ;
  16. if (y == null) return -;
  17. int result = string.Compare(x.FirstName, y.FirstName);
  18. if (result == )
  19. result = string.Compare(x.LastName, x.LastName);
  20. return result;
  21. };
  22. Array.Sort<Person>(people, compare);
  23. foreach (var item in people)
  24. {
  25. if (item == null)
  26. Console.WriteLine("null");
  27. else
  28. Console.WriteLine(item.ToString());
  29. }
  30. Console.ReadKey();
  31. }
  32. public class Person
  33. {
  34. public string FirstName { get; set; }
  35. public string LastName { get; set; }
  36. public override string ToString()
  37. {
  38. return this.FirstName + " " + this.LastName;
  39. }
  40. }

综合上面的三种方法,个人推荐第三种方法,进行自定义类型数组的排序工作,当然如果排序的逻辑很复杂,第三种未必就是最好的.

C# 数组基础的更多相关文章

  1. Java 数组基础

    数组 数组(Array):相同类型数据的集合. 定义数组 方式1(推荐,更能表明数组类型) type[] 变量名 = new type[数组中元素的个数]; 比如: int[] a = new int ...

  2. Java 数组基础,java.util.Arrays

    定义数组 方式1(推荐,更能表明数组类型) 方式2(同C语言) 方式3定义时直接初始化 数组运用基础 数组长度 equals() 数组元素不为基本数据类型时 二维数组 二维数组基础 变长的二维数组 j ...

  3. PHP 数组基础知识

    php 数组基础知识function abc($a,$b,$c = 0){ echo $a,$b,$c;}abc(1,3); //调用方法 ////可变参数function def(){ $arr = ...

  4. 1.2 NumPy数组基础

    目录 第一章 numpy入门 1.2 numpy数组基础 1.2.1 数组的属性 1.2.2 数组的索引:获取单个元素 1.2.3 数组切片:获取子数组 1.2.4 数组的变形 1.2.5 数组的拼接 ...

  5. js数组基础整理

    首页: 主要整理了一下数组中常用的一些基础知识,代码都是自己手敲,有不对的地方希望能指出,目前只有4篇,后续会不断的增加这一板块. 由于少于100字不能发所以把一些最基本的创建数组也写上. // 创建 ...

  6. JavaScript数组基础编程题归纳

    之前的随笔"JavaScript中数组类型的属性和方法"中有介绍很多数组类型的方法,但都是一些理论.最近在练习在线编程题,发现自己还是习惯于用常规的循环来答题,对于数组的方法的使用 ...

  7. java数组基础

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  8. java数组基础知识

    数组的定义:int[] array=new array[n];int array[]={, , , ,};定义了数组,JVM就会给其一个空间,数组是应用类型的数据类型,其存储方式是随机存储. 数组的遍 ...

  9. Array数组基础

    数组的定义 数组(array)是按次序排列的一组值,单个值称为元素,它们的位置都有编号(从0开始).整个数组用方括号表示. var arr = ['a', 'b', 'c']; 上面代码中的a.b.c ...

随机推荐

  1. python使用git进行版本控制-分支管理

    1.远程克隆 最好的方式是先创建远程库,然后,从远程库克隆: 首先在github上创建一个新的仓库,名字叫gitskills 我们勾选Initialize this repository with a ...

  2. 使用VMWare12.0安装Ubuntu系统

    使用VMWare12.0安装Ubuntu系统 Vmware12的虚拟机的文档说明: http://pubs.vmware.com/workstation-12/index.jsp#com.vmware ...

  3. eclipse中配置server中选择tomcat8无法进行下一步处理

    在创建server的时候,选择tomcat8后,server name为空,并且无法手动输入,同时无法进行下一步操作. 解决方案如下: 1.退出eclipse. 2.找到eclipse[工作空间][当 ...

  4. Postgres的TOAST技术

    一.介绍 首先,Toast是一个名字缩写,全写是The OverSized Attribute Storage Technique,即超尺寸字段存储技术,顾名思义,是说超长字段在Postgres的一个 ...

  5. 在权限受限制的AD域环境中部署SQL Server AlwaysOn高可用性

    最近在给一个客户部署基于微软TFS的软件生命周期管理平台时,客户要求数据库层实现高可用性,减少因数据库服务器故障影响软件开发进展. 客户现有域是一台搭建在Windows Server 2008上的级别 ...

  6. TSQL--集合处理

    UNION ALL 返回两个结果集中所有的行,返回结果集中会存在重复行 UNION 返回两个结果集中去重的行,返回结果集中无重复行 INTERSECT 返回两个结果集都有的行,返回结果集中无重复行 E ...

  7. Dockerfile文件参数详解

    参考: https://www.jianshu.com/p/e4b31ca37043 https://blog.csdn.net/u010246789/article/details/54139168 ...

  8. ADB模块源码分析(二)——adb server的启动

    1. ADB Server的启动 前面我们讲到adb模块的源码在system/core/adb下面,通过查看Android.mk文件我们了解到这个adb 模块回编译生成连个可执行文件adb.adbd, ...

  9. iOS开发常见无法分类的小问题

    iOS去除api过期警告提示

  10. “全栈2019”Java第一百零三章:匿名内部类详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...