详解c#中Array,ArrayList与List<T>的区别、共性与相互转换

目录
  • Array,ArrayList and List<T>
  • Array
    • 一维数组
      • 定义
      • 初始化赋值
    • 多维数组
      • 定义
      • 初始化赋值
      • 元素赋值和获取元素
    • 交错数组
      • 定义
      • 初始化赋值
      • 获取元素和单个赋值
    • 方法和属性
      • 获取长度
      • Array.ConvertAll() 数据类型转换
      • 切片
      • 获取单个元素和赋值
      • Array.ForEach 循环
  • ArrayList
    • 定义
    • 初始化赋值
    • 循环
    • 方法和属性
  • List<T>
    • 定义
    • 初始化
    • 循环
    • 方法和属性
      • 属性 长度
      • 属性 取值
      • 切片
      • 循环
      • 数据类型转换
  • 区别
  • Array,ArrayList and List<T>之间的转换
    • Array转ArrayList
    • Array转List<T>
    • List<T>转Array
    • List<T>转ArrayList
    • ArrayList转Array
  • 数组的打印
    • Array的打印
    • ArrayList的打印
    • List<T>的打印

Array,ArrayList and List<T>

Array、ArrayList和List都是从IList派生出来的,它们都实现了IEnumerable接口

从某种意义上来说,ArrayList和List属于集合的范畴,因为他们都来自程序集System.Collections,但是因为它们都是储存了多个变量的数据结构,并且都不是类似键值对的组合,并且没有先进先出或者先进后出的机制,故而称为数组。

我们一般称呼Array,ArrayList and List<T>为数组。

Array

Array必须在定义且不初始化赋值的时候(不初始化的情况下声明数组变量除外)必须定义数组最外侧的长度。比如:

int[] vs = new int[10];
int[,] duoWei = new int[3, 4];
int[][] jiaoCuo = new int[3][]; // 该数组是由三个一维数组组成的

一维数组

定义

用类似于这种方式定义一个数组

int[] array = new int[5];

初始化赋值

用类似于这种方式初始化

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

也可以进行隐式初始化

int[] array2 = { 1, 3, 5, 7, 9 };
string[] weekDays2 = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

用类似于下面这种方式先声明,再赋值

int[] array3;
array3 = new int[] { 1, 3, 5, 7, 9 };   // OK
//array3 = {1, 3, 5, 7, 9};   // Error

多维数组

数组可具有多个维度。多维数组的每个元素是声明时的数组所属类型的元素。比如说int[,]的每个元素都是int类型而不是int[]类型。换种说法就是多维数组不能算做“数组组成的数组”。

定义

用类似下面这种方式声明一个二维数组的长度

int[,] array = new int[4, 2];

初始化赋值

用类似于下面的方式初始化多维数组:

// Two-dimensional array.
int[,] array2D = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// The same array with dimensions specified.
int[,] array2Da = new int[4, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };
// A similar array with string elements.
string[,] array2Db = new string[3, 2] { { "one", "two" }, { "three", "four" },
                                        { "five", "six" } };

// Three-dimensional array.
int[,,] array3D = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } },
                                 { { 7, 8, 9 }, { 10, 11, 12 } } };

还可在不指定级别的情况下初始化数组

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

不初始化的情况下声明数组变量:

int[,] array5;
array5 = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };   // OK
//array5 = {{1,2}, {3,4}, {5,6}, {7,8}};   // Error

元素赋值和获取元素

可以用类似于array[1,2]的方式来获取数组的值和为数组赋值。

GetLength(0)可以获取最外围数组的长度,GetLength(1)可以获得第二层数组的长度。以此类推。为一个二维数组duoWei循环赋值的方式如下:

Console.WriteLine("二维数组赋值");
for (int i = 0; i < duoWei.GetLength(0); i++)
{
    for (int j = 0; j < duoWei.GetLength(1); j++)
    {
        duoWei[i, j] = i + j;
    }
}

如何获取二维数组中的元素个数呢?

int[,] array = new int[,] {{1,2,3},{4,5,6},{7,8,9}};//定义一个3行3列的二维数组
int row = array.Rank;//获取维数,这里指行数
int col = array.GetLength(1);//获取指定维度中的元素个数,这里也就是列数了。(0是第一维,1表示的是第二维)
int col = array.GetUpperBound(0)+1;//获取指定维度的索引上限,在加上一个1就是总数,这里表示二维数组的行数
int num = array.Length;//获取整个二维数组的长度,即所有元的个数

来源:C#中如何获取一个二维数组的两维长度,即行数和列数?以及多维数组各个维度的长度?

交错数组

交错数组是一个数组,其元素是数组,大小可能不同。 交错数组有时称为“数组的数组”。

交错数组不初始化就声明的方式如下:

int[][] ccf;
ccf = new int[3][];

交错数组类似于python的多维数组,比较符合人类的直觉,一个交错数组里面包含了多个数组。

定义

可以采用类似下面的方式来声明一个交错数组:

// 定义多维数组要求每个维度的长度都相同 下面定义交错数组
int[][] jiaoCuo = new int[3][]; // 该数组是由三个一维数组组成的

上面声明的数组是具有三个元素的一维数组,其中每个元素都是一维整数数组。

可使用初始化表达式通过值来填充数组元素,这种情况下不需要数组大小。 例如:

jaggedArray[0] = new int[] { 1, 3, 5, 7, 9 };
jaggedArray[1] = new int[] { 0, 2, 4, 6 };
jaggedArray[2] = new int[] { 11, 22 };

初始化赋值

可在声明数组时将其初始化,如:

int[][] jaggedArray2 = new int[][]
{
new int[] { 1, 3, 5, 7, 9 },
new int[] { 0, 2, 4, 6 },
new int[] { 11, 22 }
};

获取元素和单个赋值

可以用类似于jiaoCuo[1][1]来获取单个元素的值,也可以用类似于jiaoCuo[1][1] = 2;来为单个元素赋值。

可以采取类似于下面的方式来进行循环赋值:

Console.WriteLine("交错数组循环赋值");
// 先声明交错数组中每一个数组的长度
for (int i = 0; i < 3; i++)
{
    jiaoCuo[i] = new int[i + 1];
}
// 然后对交错数组中的每一个元素赋值
for (int i = 0; i < jiaoCuo.Length; i++)
{
    Console.WriteLine($"交错数组的第{i + 1}层");
    for (int j = 0; j < jiaoCuo[i].Length; j++)
    {
        jiaoCuo[i][j] = i + j;
        Console.WriteLine(jiaoCuo[i][j]);
    }
}

方法和属性

像数组这种储存多个变量的数据结构,最重要的就是增查删改、获取长度和数据类型转换。Array因为数组的特性,长度不可改变,所以增查删改只能有查和改。

Array类型用用类似于下面的方式进行改操作:

vs[0] = 12; //一维数组
duoWei[1, 2] = 3; //多维数组
jiaoCuo[1][1] = 2; //交错数组

Array类型用类似于下面的方式进行查操作:

int[] vs = new int[10];
vs[0] = 12;
Console.WriteLine(Array.IndexOf(vs, 12)); //0
Console.WriteLine(vs.Contains(12)); // True

获取长度

可以用类似于下面这种方式来获取:

Console.WriteLine(vs.Length);
Console.WriteLine(vs.Count());

交错数组的Length是获取所包含数组的个数,多维数组的Length是获取数组的元素的总个数,多维数组GetLength(0)可以获取最外围数组的长度,GetLength(1)可以获得第二层数组的长度。以此类推。

Array.ConvertAll() 数据类型转换

可以用Array.ConvertAll<TInput,TOutput>(TInput[], Converter<TInput,TOutput>) 来进行数组类型的转换。

参数如下:

  • array
    TInput[]

要转换为目标类型的从零开始的一维 Array

用于将每个元素从一种类型转换为另一种类型的 Converter

来源:[Array.ConvertAll(TInput], Converter) 方法 (System) | Microsoft Docs

demo如下:

double[] vs3 = Array.ConvertAll(vs, item => (double)item);

切片

默认状态下只能对一维数组进行切片,或者通过交错数组获取的一维数组也可以进行切片。

切片的方式类似于vs[1..5],表示vs数组从1到5,左闭右开。^1表示-1,即最后一个元素。[^3..^1]表示倒数第三个元素到倒数第一个元素,左闭右开。

获取单个元素和赋值

可以采用下面的方式来获取单个元素和为单个元素单独赋值:

// 一维数组
Console.WriteLine(vs[1]);
vs[1] = 2;
// 多维数组
Console.WriteLine(duoWei[1, 2]);
duoWei[1, 2] = 3;
// 交错数组
Console.WriteLine(jiaoCuo[1][0]);
jiaoCuo[1][0] = 0;

Array.ForEach 循环

System.Array里面也有ForEach方法,这是用于Array的。

demo:

Array.ForEach(vs, item => Console.WriteLine(item));

ArrayList

定义

用类似于下面的三种方式中的任意一种来声明ArrayList:

ArrayList() 初始化 ArrayList 类的新实例,该实例为空并且具有默认初始容量。
ArrayList(ICollection) 初始化 ArrayList 类的新实例,该类包含从指定集合复制的元素,并具有与复制的元素数相同的初始容量。
ArrayList(Int32) 初始化 ArrayList 类的新实例,该实例为空并且具有指定的初始容量。

可以将Arraylist看作是一种长度可以自由变换,可以包含不同数据类型元素的数组。

初始化赋值

可以采用类似于下面的方式来初始化赋值:

ArrayList arrayList1 = new ArrayList() { 12, 334, 3, true };

循环

循环可以用for和foreach。

foreach (var item in arrayList)
{
    Console.WriteLine(item);
}

方法和属性

list<T>类似,但是没有ConvertAll方法。ArrayList本身没有ForEach方法,但是也可以用传统的foreach方法(就像前面提到的ArrayList的循环那样)。

具体的方法和属性请查看List部分的方法和属性

List<T>

定义

用类似于下面的三种方式中的任意一种来声明List<T>

List() 初始化 List 类的新实例,该实例为空并且具有默认初始容量。
List(IEnumerable) 初始化 List 类的新实例,该实例包含从指定集合复制的元素并且具有足够的容量来容纳所复制的元素。
List(Int32) 初始化 List 类的新实例,该实例为空并且具有指定的初始容量。

初始化

用类似于下面的方式在声明时初始化:

List<string> listA = new List<string>() { "hello", " ", "wrold" };

循环

List<T>有一个名称为ForEach的方法:

public void ForEach (Action<T> action);

该方法的本质是要对 List 的每个元素执行的 Action 委托。Action 的参数即为List<T>在循环过程中的每个元素。

demo如下:

// 声明
List<string> listA = new List<string>() { "hello", " ", "wrold" };
// 循环
var i = 0;
listA.ForEach(item =>
              {
                  Console.WriteLine($"第{i + 1}个");
                  Console.WriteLine(item);
                  i++;
              });

方法和属性

从获取长度、增查删改、数据类型转换、切片和循环来解析。其中除了数据类型转换和List<T>类型本身就拥有的ForEach方法外,都适用于ArrayList。

先声明一个List<string>作为演示的基础:

List<string> listA = new List<string>() { "hello", " ", "wrold" };

属性 长度

Count属性可以获取长度

Console.WriteLine(listA.Count);

属性 取值

Console.WriteLine(listA[0]);

即增加元素,可以用Add方法:

listA.Add("12");

IndexOf获取所在位置,Contains获取是否包含。

Console.WriteLine(listA.IndexOf("12"));
Console.WriteLine(listA.Contains("12"));

Remove根据数据删除,RemoveAt根据位置删除。

listA.Remove("12");
listA.RemoveAt(1);

可以用类似于listA[1] = "改变";的方式来修改元素内容。

切片

可以用GetRange(int index, int count)来进行切片操作,第一个参数是切片开始的位置,第二个参数是切片的数量,即从index开始往后数几个数。

Console.WriteLine(listA.GetRange(1, 1).Count);

循环

List<T>有一个名称为ForEach的方法,该方法的本质是要对 List 的每个元素执行的 Action 委托。Action 的参数即为List<T>在循环过程中的每个元素。

demo如下:

// 声明
List<string> listA = new List<string>() { "hello", " ", "wrold" };
// 循环
var i = 0;
listA.ForEach(item =>
              {
                  Console.WriteLine($"第{i + 1}个");
                  Console.WriteLine(item);
                  i++;
              });

数据类型转换

可以用ConvertAll来对数组的数据类型进行转换,这是List<T>自带的方法。System.Array里面也有ConvertAll方法,这是用于Array的。

List<object> listObject = listA.ConvertAll(s => (object)s);

区别

成员单一类型 长度可变 切片友好 方法丰富 增查删改 ConvertAll
一维数组 查、改
多维数组 查、改
交错数组 查、改
ArrayList 增查删改
List<T> 增查删改

Array最大的好处就是切片友好,可以使用类似于[1..3]的方式切片,这是比GetRange更加直观的切片方式。List<T>类型可以通过ToArray的方法来转变成Array。

Array,ArrayList and List<T>之间的转换

关于这一部分的demo代码详情可从Array,ArrayList and List之间的转换 · sogeisetsu/Solution1@88f27d6 (github.com)获得。

先分别声明这三种数据类型。

// 声明数组
int[] a = new int[] { 1,3,4,5,656,-1 };
// 声明多维数组
int[,] aD = new int[,] { { 1, 2 }, { 3, 4 } };
// 声明交错数组
int[][] aJ = new int[][] {
    new int[]{ 1,2,3},
    new int[]{ 1}
};
// 声明ArrayList
ArrayList b = new ArrayList() { 1, 2, 344, "233", true };
// 声明List<T>
List<int> c = new List<int>();

Array转ArrayList

// 数组转ArrayList
ArrayList aToArrayList = new ArrayList(a);

Array转List<T>

List<int> aToList = new List<int>(a);
List<int> aToLista = a.ToList();

List<T>转Array

int[] cToList = c.ToArray();

List<T>转ArrayList

ArrayList cToArrayList = new ArrayList(c);

ArrayList转Array

// ArrayList转Array
object[] bToArray = b.ToArray();

在转换的过程中,会丢失数据类型的准确度,简单来说就是转换成的Array会变成object

这种转换的意义不大,如果转换完之后再强行用Array.ConvertAll方法来进行数据类型的转换,很有可能会出现诸如Unable to cast object of type 'System.String' to type 'System.Int32'.的错误,这是因为ArrayList本身成员就可以不是单一类型。

数组的打印

Array的打印

对于Array的打印,我找到了四种方式,如下:

调用Array.ForEach

Array.ForEach(a, item => Console.WriteLine(item));

传统forEach

foreach (var item in a)
{
Console.WriteLine(item);
}

传统for

for (int i = 0; i < a.Count(); i++)
{
Console.WriteLine(a[i]);
}

string.Join

Console.WriteLine(string.Join("\t", a));

ArrayList的打印

ArrayList的打印我知道的就只有传统的for和foreach两种方式。

List<T>的打印

List<T>的打印除了传统的for和foreach两种方式之外,还有List<T>本身自带的foreach:

var i = 0;
listA.ForEach(item =>
              {
                  Console.WriteLine($"第{i + 1}个");
                  Console.WriteLine(item);
                  i++;
              });

请注意:ArrayList和List<T>均没有string.Join和调用Array.ForEach两种方式来打印数组。

到此这篇关于详解c#中Array,ArrayList与List<T>的区别、共性与相互转换的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#常见的几种集合 ArrayList,Hashtable,List<T>,Dictionary<K,V> 遍历方法对比

    一.先来分别介绍一下ArrayList,Hashtable,List<T>,Dictionary<K,V> 1.ArrayList动态数组,保存值的时候比较好用 2.Hashtable以存储键值对的方式存储.value,和key 3.List<T> 和 Dictionary<K,V> 应该是泛型吧,可以保存实体类 二.各种集合的遍历方法演示 1.ArrayList ArrayList list = new ArrayList(); //for遍历 for (

  • C#中数组Array,ArrayList,泛型List详细对比

    在C#中数组Array,ArrayList,泛型List都能够存储一组对象,但是在开发中根本不知道用哪个性能最高,下面我们慢慢分析分析. 一.数组Array 数组是一个存储相同类型元素的固定大小的顺序集合.数组是用来存储数据的集合,通常认为数组是一个同一类型变量的集合. Array 类是 C# 中所有数组的基类,它是在 System 命名空间中定义. 数组在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也非常简单. Array数组具体用法: using System; names

  • C#中数组、ArrayList和List三者的区别详解

    在C#中数组,ArrayList,List都能够存储一组对象,那么这三者到底有什么样的区别呢. 数组 数组在C#中最早出现的.在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单. //数组 string[] s=new string[2]; //赋值 s[0]="a"; s[1]="b"; //修改 s[1]="a1"; 但是数组存在一些不足的地方.在数组的两个数据间插入数据是很麻烦的,而且在声明数组的时候必须指定数组的长度

  • 解析C#中[],List,Array,ArrayList的区别及应用

    [] 是针对特定类型.固定长度的. List 是针对特定类型.任意长度的. Array 是针对任意类型.固定长度的. ArrayList 是针对任意类型.任意长度的. Array 和 ArrayList 是通过存储 object 实现任意类型的,所以使用时要转换. 应用示例 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web

  • C#中数组、ArrayList和List三者的区别详解及实例

    在C#中数组,ArrayList,List都能够存储一组对象,那么这三者到底有什么样的区别呢. 数组 数组在C#中最早出现的.在内存中是连续存储的,所以它的索引速度非常快,而且赋值与修改元素也很简单. //数组 string[] s=new string[2]; //赋值 s[0]="a"; s[1]="b"; //修改 s[1]="a1"; 但是数组存在一些不足的地方.在数组的两个数据间插入数据是很麻烦的,而且在声明数组的时候必须指定数组的长度

  • 详解c#中Array,ArrayList与List<T>的区别、共性与相互转换

    目录 Array,ArrayList and List<T> Array 一维数组 定义 初始化赋值 多维数组 定义 初始化赋值 元素赋值和获取元素 交错数组 定义 初始化赋值 获取元素和单个赋值 方法和属性 改 查 获取长度 Array.ConvertAll() 数据类型转换 切片 获取单个元素和赋值 Array.ForEach 循环 ArrayList 定义 初始化赋值 循环 方法和属性 List<T> 定义 初始化 循环 方法和属性 属性 长度 属性 取值 增 查 删 改 切

  • 详解Java中Checked Exception与Runtime Exception 的区别

    详解Java中Checked Exception与Runtime Exception 的区别 Java里有个很重要的特色是Exception ,也就是说允许程序产生例外状况.而在学Java 的时候,我们也只知道Exception 的写法,却未必真能了解不同种类的Exception 的区别. 首先,您应该知道的是Java 提供了两种Exception 的模式,一种是执行的时候所产生的Exception (Runtime Exception),另外一种则是受控制的Exception (Checked

  • 详解Python中sorted()和sort()的使用与区别

    目录 sort()方法是什么 如何妙用sorted() 方法 总结 在 Python 中,你可以使用 sorted() 方法或 sort() 方法对数据进行排序. 在本文中,我将提供 sorted() 和 sort() 方法的代码示例,并解释两者之间的区别. sort()方法是什么 此方法接受一个列表并对其进行排序.但,请记住此方法没有返回值,即返回None. 下面例子中,我们有一个数字列表,我们可以使用 sort() 方法按升序对列表进行排序. my_list = [67, 2, 999, 1

  • 详解Vue中Computed与watch的用法与区别

    目录 computed computed只接收一个getter函数 computed同时接收getter函数对象和setter函数对象 调试 Computed watchEffect 立即执行 监听基本数据类型 停止watchEffect 清理watchEffect watchPostEffect 和 watchSyncEffect watchEffect不能监听对象 watch 监听单个数据 监听多个数据(传入数组) 官方文档总结 computed watchEffect watch comp

  • 详解JS中continue关键字和break关键字的区别

    目录 1.框架 2.简单介绍 3.代码演示 4.演示break 1.框架 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <script> </script> </body> </html> 2.简单介绍 1.在javascr

  • 详解js中let与var声明变量的区别

    ES6 新增了let命令,用来声明局部变量,所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束. 1.ES6可以用let定义块级作用域变量 代码如下: function f1(){ { var a = 10; let b = 20; } console.log(a); // 10 console.log(b); // Uncaught ReferenceError: b is not defined } f1(); 说明:在ES6之前只有全局作用域和函数作用域,在ES6中新增

  • 详解Java中的checked异常和unchecked异常区别

    (一)Java的异常层次结构 要想明白Java中checked Exception和unchecked Exception的区别,我们首先来看一下Java的异常层次结构. 这是一个简化的Java异常层次结构示意图,需要注意的是所有的类都是从Throwable继承而来,下一层则分为两个结构,Error和Exception.其中Error类层次描述了Java运行时系统的内部错误和资源耗尽错误,这种错误除了简单的报告给用户,并尽力阻止程序安全终止之外,一般也米有别的解决办法了. (二)unchecke

  • 详解sql中exists和in的语法与区别

    exists和in的区别很小,几乎可以等价,但是sql优化中往往会注重效率问题,今天咱们就来说说exists和in的区别. exists语法: select - from table where exists (子查询) 将主查询的结果,放到子查询结果中进行校验,如子查询有数据,则校验成功,那么符合校验,保留数据. create table teacher ( tid int(3), tname varchar(20), tcid int(3) ); insert into teacher va

  • 详解java中String、StringBuilder、StringBuffer的区别

    你知道String.StringBuilder.Stringbuffer的区别吗?当你创建字符串的时候,有考虑过该使用哪个吗? 别急,这篇文章带你解决这些问题. 可变性 首先,String是字符串,我们一般这样声明: String s = "abc"; String类使用被final修饰的char数组来存储字符串的内容,它的一大特性就是不可变,怎么理解这个不可变呢? 我们知道,一个类被final修饰,那么这个类无法被继承,方法也不能被重写,属性也不能改变. 看看这段代码: String

  • 详解JS中Array对象扩展与String对象扩展

    废话不多说了,直接给大家上array对象扩展代码了,具体代码如下所示: /** * Created by laixiangran on 2016/01/07. * Array扩展 */ (function() { // 遍历数组 if (typeof Array.prototype.forEach != "function") { Array.prototype.forEach = function (fn, context) { for (var i = 0; i < this

随机推荐