我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈C#数组(一)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈C#数组(一)

前言:

  如果需要使用同一类型的多个对象,可以使用数组和集合。C#用特殊的记号声明,初始化和使用数组。Array类在后台发挥作用,它为数组中的元素排序和过滤提供了多个方法。使用枚举器,可以迭代数组中的所有元素。
  如果需要使用不同类型的多个对象,可以使用Tuple(元组)类型。

一.简单数组之一维数组  

    数组是一种数据结构,它可以包含同一个类型的多个元素。

1.数组的声明  

      在声明数组时,先定义数组中的元素类型,其后是一对空方括号和一个变量名。


  int[] myArray;

2.数组的初始化

  声明了数组之后,就必须为数组分配内存,以保存数组的所有元素。数组是引用类型,所以必须给它分配堆上的内存。为此,应使用new运算符,指定数组中元素的类型和数量来初始化数组的变量。


  myArray = new int[4];


  在声明和初始化数组后,变量myArray就引用了4个整数值,它们位于托管堆上:

   在指定了数组的大小后,就不能重新设置数组的大小。如果事先不知道数组中应包含多少个元素,就可以使用集合。
  除了在两个语句中声明和初始化数组之外,还可以在一个语句中声明和初始化数组:


  int[] myArray = new int[4];


  还可以使用数组初始化器为数组的每个元素复制。数组初始化器只能在声明数组变量时使用,不能在声明数组之后使用。


  int[] myArray = new int[4]{1,3,5,7};


  如果用花括号初始化数组,可以不指定数组的大小,因为编译器会自动统计元素的个数:


  int[] myArray = new int[]{1,3,5,7};


  也可以使用更简单的形式:


  int[] myArray = {1,3,5,7};


3.访问数组元素

  在声明和初始化数组之后,就可以使用索引器访问其中的元素了。数组只支持有整型参数的索引器。
  索引器总是以0开头,表示第一个元素。可以传递给索引器的最大值是元素个数减1,因为索引从0开始:


  int[] myArray = {1,3,5,7};
  int v1 = myArray[0];
  int v2 = myArray[1];
  myArray[3] = 4;

  可以使用数组的Length属性获取元素的个数。

4.数组中使用引用类型

  数组除了能声明预定义类型的数组,还可以声明自定义类型的数组。


 public class Person
  {
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public override string ToString()
    {
      return String.Format("{0} {1}", FirstName, LastName);
    }
  }

  Person[] myPersons = new Person[2];
  myPersons[0] = new Person { FirstName = "Ayrton", LastName = "Senna" };
  myPersons[1] = new Person { FirstName = "Michael", LastName = "Schumacher" };

  如果数组中的元素是引用类型,就必须为每个数组元素分配内存。如果使用了数组中未分配内存的元素,就会抛出NullReferenceException类型的异常。
  下面是内存情况:

    对自定义类型也可以使用数组初始化器:


  Person[] myPersons2 =
  {
    new Person { FirstName="Ayrton", LastName="Senna"},
    new Person { FirstName="Michael", LastName="Schumacher"}
  };

二.多维数组

  多维数组用两个或多个整数来索引。
  在C#中声明多维数组,需要在方括号中加上逗号。数组在初始化时应指定每一维的大小(也称为阶)。


  int[,] twoDim = new int[3,3];
  twoDim[0,0] = 1;
  twoDim[0,1] = 2;
  twoDim[0,2] = 3;
  twoDim[1,0] = 4;
  twoDim[1,1] = 5;
  twoDim[1,2] = 6;
  twoDim[2,0] = 7;
  twoDim[2,1] = 8;
  twoDim[2,2] = 9;

  声明数组之后,就不能修改其阶数了。
  也可以使用初始化器来初始化多维数组:


  int[,] twoDim ={
    {1,2,3},
    {4,5,6},
    {7,8,9}
    };


  使用数组初始化器时,必须初始化数组的每个元素,不能遗漏任何元素。
  声明一个三位数组:


  int[,,] threeDim ={
    {{1,2},{3,4}},
    {{5,6},{7,8}},
    {{9,10},{11,12}}
    };
  Console.WriteLine(threeDim[0,1,1]);

三.锯齿数组

  二维数组的大小对应于一个矩形,而锯齿数组的大小设置比较灵活,在锯齿数组中,每一行都可以有不同的大小。
  在声明锯齿数组时,要依次放置左右括号。在初始化锯齿数组时,只在第一对方括号中设置该数组包含的行数。定义各行中元素个数的第二个方括号设置为空,因为这类数组的每一行包含不同的元素个数。之后,为每一行指定行中的元素个数:


  int[][] jagged = new int[3][];
  jagged[0] = new int[2]{1,2};
  jagged[1] = new int[4]{3,4,5,6};
  jagged[2] = new int[3]{7,8};


  迭代锯齿数组中的所有元素的代码可以放在嵌套的for循环中。在外层的for循环中迭代每一行,在内层的for循环中迭代一行中的每个元素:


  for(int row = 0;row<jagged.Length;row++)
  {
    for(int element = 0;element<jagged[row].Length;element++)
    {
      Console.WriteLine("row:{0}, element:{1},value:{2}",row,element,jagged[row][element]);
    }
  }

四.Array类

  用方括号声明数组是C#中使用Array类的表示法。在后台使用C#语法,会创建一个派生自抽象基类Array的新类。这样,就可以使用Array类为每个C#数组定义的方法和属性了。
  Array类实现的其它属性有LongLengthRank。如果数组包含的元素个数超出了整数的取值范围,就可以使用LongLength属性来获得元素个数。使用Rank属性可以获得数组的维数。

1.创建数组

  Array类是一个抽象类,所以不能使用构造函数来创建数组。但除了使用C#语法创建数组实例之外,还可以使用静态方法CreateInstance()创建数组。如果事先不知道元素的类型,该静态方法就很有用,因为类型可以作为Type对象传递给CreateInstance()方法。
  CreateInstance()方法的第一个参数是元素的类型,第二个参数定义数组的大小。
  可以使用SetValue()方法设置对应元素的值,用GetValue()方法读取对应元素的值。


  Array intArray1 = Array.CreateInstance(typeof(int), 5);
  for (int i = 0; i < 5; i++)
  {
    intArray1.SetValue(33, i);
  }

  for (int i = 0; i < 5; i++)
  {
    Console.WriteLine(intArray1.GetValue(i));
  }
  

      还可以将已经创建的数组强制转换称声明为int[]的数组:


  int[] intArray2 = (int[])intArray1;


  CreateInstance()方法有许多重载版本,可以创建多维数组和索引不基于0的数组。

  


//创建一个2X3的二维数组,第一维基于1,第二维基于10:
  int[] lengths = { 2, 3 };
  int[] lowerBounds = { 1, 10 };
  Array racers = Array.CreateInstance(typeof(Person), lengths, lowerBounds);

 
  racers.SetValue(new Person { FirstName = "Alain", LastName = "Prost" }, index1: 1, index2: 10);
  racers.SetValue(new Person
  {
    FirstName = "Emerson",
    LastName = "Fittipaldi"
  }, 1, 11);
  racers.SetValue(new Person { FirstName = "Ayrton", LastName = "Senna" }, 1, 12);
  racers.SetValue(new Person { FirstName = "Michael", LastName = "Schumacher" }, 2, 10);
  racers.SetValue(new Person { FirstName = "Fernando", LastName = "Alonso" }, 2, 11);
  racers.SetValue(new Person { FirstName = "Jenson", LastName = "Button" }, 2, 12);

  Person[,] racers2 = (Person[,])racers;
  Person first = racers2[1, 10];
  Person last = racers2[2, 12];

2.复制数组

  因为数组是引用类型,所以将一个数组变量赋予另一个数组变量,就会得到两个引用同一数组的变量。
  数组实现ICloneable接口。这个接口定义的Clone()方法会复制数组,创建数组的浅表副本。

  如果数组的元素是值类型,Clone()方法会复制所有值:


  int[] a1 = {1,2};
  int[] a2 = (int[])a1.Clone();


  如果数组包含引用类型,只复制引用。

  除了使用Clone()方法之外,还可以使用Array.Copy()方法创建浅表副本。


 Person[] beatles = {
    new Person { FirstName="John", LastName="Lennon" },
    new Person { FirstName="Paul", LastName="McCartney" }
  };

  Person[] beatlesClone = (Person[])beatles.Clone();
  Person[] beatlesClone2 = new Person[2];
  Array.Copy(beatlesClone,beatlesClone2,2);//注意与Clone的语法区别,Copy需要传递阶数相同的已有数组。(还可以使用CopyTo()方法)

3.排序

  Array类使用快速排序算法对数组中的元素进行排序。Sort()方法需要数组中的元素实现IComparable接口。因为简单类型(如String,Int32)实现IComparable接口,所以可以对包含这些类型的元素排序。


    string[] names = {
    "Christina Aguilera",
    "Shakira",
    "Beyonce",
    "Gwen Stefani"
    };

    Array.Sort(names);

    foreach (string name in names)
    {
      Console.WriteLine(name);
    }


  如果对数组使用使用自定义类,就必须实现IComparable接口。这个接口只定义了一个方法CompareTo()方法,如果要比较的对象相等,该方法就返回0.如果该实例应排在参数对象的前面,该方法就返回小于i0de值。如果该实例应排在参数对象的后面,该方法就返回大于0的值。


  public class Person : IComparable<Person>
  {
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public override string ToString()
    {
      return String.Format("{0} {1}",
      FirstName, LastName);
    }

    public int CompareTo(Person other)
    {
      if (other == null) throw new ArgumentNullException("other");

      int result = this.LastName.CompareTo(other.LastName);
      if (result == 0)
      {
        result = this.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)
  {
    Console.WriteLine(p);
  }

  如果Person对象的排序方式与上述不同,或者不能修改在数组中用作元素的类,就可以实现IComparer接口或IComparer<T>接口。这两个接口定义了方法Compare()方法。机型比较的类必须实现这两个接口之一。


  public enum PersonCompareType
  {
    FirstName,
    LastName
  }
  //通过使用实现了IComparer<T> 泛型接口的PersonComparer类比较Person对象数组。
  public class PersonComparer : IComparer<Person>
  {
    private PersonCompareType compareType;

    public PersonComparer(PersonCompareType compareType)
    {
      this.compareType = compareType;
    }


    #region IComparer<Person> Members

    public int Compare(Person x, Person y)
    {
        if (x == null) throw new ArgumentNullException("x");
        if (y == null) throw new ArgumentNullException("y");

      switch (compareType)
      {
        case PersonCompareType.FirstName:
          return x.FirstName.CompareTo(y.FirstName);
        case PersonCompareType.LastName:
          return x.LastName.CompareTo(y.LastName);
        default:
          throw new ArgumentException(
          "unexpected compare type");
      }
    }

    #endregion
  }

  客户端代码:

 


 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,
  new PersonComparer(PersonCompareType.FirstName));

  foreach (Person p in persons)
  {
    Console.WriteLine(p);
  }

五.数组作为参数

  数组可以作为参数传递给方法,也可以从方法中返回。

1.数组协变

  数组支持协变。这表示数组可以声明为基类,其派生类型的元素可以赋值于数组元素。


  static void DisPlay(object[] o)
  {
    //..
  }

  可以给该方法传递一个Person[]
  数组协变只能用于引用类型,不能用于值类型。

2.ArraySegment<T>

  结构ArraySegment<T>表示数组的一段。如果需要使用不同的方法处理某个大型数组的不同部分,那么可以把相应的数组部分复制到各个方法。

  ArraySegment<T>结构包含了关于数组段的信息(偏移量和元素个数)。


  static void Main()
  {
    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)
    };


    var sum = SumOfSegments(segments);
    Console.WriteLine("sum of all segments: {0}", sum);

  }

  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;
  }

  数组段不复制原数组的元素,但原数组可以通过ArraySegment<T>访问。如果数组段中的元素改变了,这些变化就会反映到原数组中。

到此这篇关于浅谈C#数组的文章就介绍到这了,更多相关C#数组内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈C#数组(一)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

浅谈一下Java线程组ThreadGroup

ThreadGroup是为了方便线程管理出现了,可以统一设定线程组的一些属性,比如setDaemon,设置未处理异常的处理方法,设置统一的安全策略等等,需要的朋友可以参考下
2023-05-19

浅谈一下JavaScript与C++的差异

这篇文章主要介绍了浅谈一下JavaScript与C++的差异,本来两门语言各有各的战场,并没什么交集,但自从 Node.js 框架出现之后,JavaScript 就摆脱了浏览器的樊笼,开始渗透进入系统应用的领域
2023-05-14

浅谈shell数组的定义及循环

shell中数组的定义及遍历,先直接看示例:#!/bin/sh #定义方法一 数组定义为空格分割 arrayWen=(a b c d e f) #定义方法二 arrayXue[0]="m" arrayXue[1]="n" array
2022-06-04

浅谈Java数组的一些使用方法及堆栈存储

数组用于存储一组同一数据类型数据的容器数组会对放入其中的数据自动编号,编号是从0开始的---下标定义格式数据类型[] 数组名 = new 数据类型[数组的大小];---可以先声明再初始化int[] arr = new int[5];---定
2023-05-31

浅谈一下Android的Activity

这篇文章主要介绍了浅谈一下Android的Activity,活动是所有安卓应用程序的门面,凡事你在应用中看到的东西,都是放到活动中的,需要的朋友可以参考下
2023-05-16

浅谈Python numpy创建空数组的问题

目录一、问题描述:二、具体的实现:三、完整代码:一、问题描述:有一个shape为(308, 2)的二维数组,以及单独的一个数字,需要保存到csv文件中,这个单独的数字让其保存到第3列第一行的位置。 二、具体的实现:首先要想把一个(308,
2022-06-02

浅谈shell 遍历数组的几种方法

背景某天遇到一个问题,现象如下:第一种遍历正常打印元素,然而第二种遍历只会打印一个元素!#!/bin/bash # $1 代表文件目录 # 执行 eg: # sh your_shell.sh /u
2022-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录