C#集合之列表的用法

目录
  • 1.创建列表
  • 2.添加元素
  • 3.插入元素
  • 4.访问元素
  • 5.删除元素
  • 6.搜索
  • 7.排序
  • 8.类型转换
  • 9.只读集合

.NET Framework为动态列表List提供泛型类List<T>。这个类实现了IList,ICollection,IEnumerable,IList<T>,ICollection<T>,IEnumerable<T>接口。

1.创建列表

创建一个赛车手类,下面的例子会用到:

public class Racer : IComparable<Racer>, IFormattable
      {
        public int Id { get; private set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Country { get; set; }
        public int Wins { get; set; }

        public Racer(int id, string firstName, string lastName, string country)
          : this(id, firstName, lastName, country, wins: 0)
        {
        }
        public Racer(int id, string firstName, string lastName, string country, int wins)
        {
          this.Id = id;
          this.FirstName = firstName;
          this.LastName = lastName;
          this.Country = country;
          this.Wins = wins;
        }

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

        public string ToString(string format, IFormatProvider formatProvider)
        {
          if (format == null) format = "N";
          switch (format.ToUpper())
          {
            case null:
            case "N": // name
              return ToString();
            case "F": // first name
              return FirstName;
            case "L": // last name
              return LastName;
            case "W": // Wins
              return String.Format("{0}, Wins: {1}", ToString(), Wins);
            case "C": // Country
              return String.Format("{0}, Country: {1}", ToString(), Country);
            case "A": // All
              return String.Format("{0}, {1} Wins: {2}", ToString(), Country, Wins);
            default:
              throw new FormatException(String.Format(formatProvider,
                    "Format {0} is not supported", format));
          }
        }

        public string ToString(string format)
        {
          return ToString(format, null);
        }

        public int CompareTo(Racer other)
        {
          if (other == null) return -1;
          int compare = string.Compare(this.LastName, other.LastName);
          if (compare == 0)
            return string.Compare(this.FirstName, other.FirstName);
          return compare;
        }
      }

调用默认的构造函数,就可以创建列表对象。在List<T>中,必须为声明为列表的值指定类型:

var intList = new List<int>();
var racers =new List<Racer>();

使用默认的构造函数创建一个空列表。元素添加到列表中后,列表的容量就会扩大为可接纳4个元素。如果添加到第五个元素,列表的大小就会重新设置为包含8个元素。如果8个元素还不够,列表的大小就会重新设置为包含16个元素。每次都会将列表容量重新设置为原来的2倍。

如果列表的容量改变了,整个集合就会重新分配到一个新的内存块中。在List<T>泛型类的实现代码中,使用了一个T类型的数组。通过重新分配内存,创建一个新数组,Array.Copy()方法将旧数组中的元素复制到新数组中。为节省时间,如果事先知道列表中的元素个数,就可以用构造函数定义其容量:

List<int> intList = new List<int>(10);

使用Capacity属性可以获取和设置集合的容量:

intList.Capacity = 20;

集合的元素个数用Count属性读取。

如果已经将元素添加到列表中,且不希望添加的更多的元素,就可以调用TrimExcess()方法,去除不需要的容量。但是,因为重新定位需要时间,所以如果元素的个数超过了容量的90%,该方法就什么也不做。

intList.TrimExcess();

还可以使用集合初始值给集合赋值:

var intList = new List<int>(){1,2};

集合初始值并没有反映在已编译的程序集的IL代码中,编译器会把集合初始值变成对初始值列表中的每一项调用Add()方法。

2.添加元素

使用Add()方法可以给列表添加元素:

intList.Add(1);
intList.Add(2);

使用AddRange()方法,可以一次给集合添加多个元素。因为AddRange()方法的参数是IEnumerable<T>类型的对象,所以可以传递一个数组:

intList.AddRange(
    new Int[]{1,2}
);

如果在实例化列表时知道集合的元素个数,就亦可以将实现IEnumerable<T>类型的对象传递给类的构造函数,类似AddRange()方法:

var intList = new List<int>(
    new Int[]{1,2}
);

3.插入元素

使用Insert()方法可以在指定位置插入元素:

intList.Insert(3,4);

方法InsertRange()可以插入大量的元素。

racers.InsertRange(3, new Racer[] {
    new Racer(12, "Jochen", "Rindt", "Austria", 6),
    new Racer(22, "Ayrton", "Senna", "Brazil", 41) });

4.访问元素

实现了IList和IList<T>接口的所有类都提供了一个索引器,可以使用索引器来访问元素:

int i = intList[0;]

String类也可以通过索引访问字符:

string s = "sdas";
char c = s[0];

因为List<T>集合类实现了IEnumerable接口,所以也可以使用foreach(https://www.jb51.net/article/244045.htm)语句遍历集合中的元素:

  foreach(int i in intList)
  {
    //..
  }

除了使用foreach语句之外,List<T>类还提供了ForEach()方法,该方法用Action<T>参数声明:

public void ForEach(Action<T> action);

.NEt实现ForEach()方法的代码如下:

  public class List<T>:ILIst<T>
  {
    private T[] items;

    //...

    public void ForEach(Action<T> action)
    {
      if(action==null) throw new ArgumentNullException("action");

      foreach(T item in items)
      {
        action(item);
      }
    }
  }

实例:

  racers.ForEach(
    r =>
    {
      Console.WriteLine(r.ToString())
    }
  );

这里使用了lambda表达式(https://www.jb51.net/article/244054.htm)。

5.删除元素

删除元素时,可以利用索引,也可以传递要删除的元素:

  var graham = new Racer(7, "Graham", "Hill", "UK", 14);
  var emerson = new Racer(13, "Emerson", "Fittipaldi", "Brazil", 14);
  var mario = new Racer(16, "Mario", "Andretti", "USA", 12);
  var racers = new List<Racer>(20) { graham, emerson, mario };
  racers.RemoveAt(3);
  racers.Remove(graham);

按索引删除比较快,因为必须在集合中搜索要删除的元素。Remove方法先在集合中搜索,用IndexOf方法获取元素的索引,再使用该索引删除元素。IndexOf方法先检查元素类型是否实现了IEquatable<T>接口。如果是,就调用这个接口的Equals()方法,确定集合中的元素是否等于传递给Equals()方法的元素。如果没有实现这个接口,就使用Object类的Equals()方法比较这些元素。Object类的Equals()方法默认实现代码对值类型进行按位比较,对引用类型只比较其引用。

RemoveRange()方法可以从集合中删除许多元素。它的第一个参数指定了开始删除的元素索引,第二个参数指定了要删除的元素个数:

  int index = 3;
  int count = 5;
  racers.RemoveRange(index,count);

要删除集合中的所有元素,可以使用ICollection<T>接口定义的Clear()方法:

  racers.Clear();

RemoveAll()方法删除有指定特性的所以元素。这个方法使用Predicate<T>类型的参数定义。下面将介绍Predicate<T>类型。

6.搜索

获得要查找的元素的索引,或者搜索元素的本身。可以使用的方法有IndexOf(),LastIndexOf(),FindIndex(),FindLastIndex(),Find(),FindLast().

如果只检查元素是否存在,可以使用Exists()方法。

IndexOf()方法需要将一个对象作为参数,如果在集合中找到该元素,这个方法就返回该元素的索引。如果没有找到就返回—1.IndexOf方法使用IEquatable<T>接口来比较元素。

使用IndexOf()方法,还可以指定不需要搜索整个集合,指定从哪个元素开始搜索以及搜索几个元素。

除了使用IndexOf()方法搜索指定元素之外,还可以搜索有某个特性的元素,该特性可以用FindIndex(),FindLastIndex(),Find(),FindLast()方法来定义,这些方法需要一个Predicate<T>类型的参数:

如:

public int FindIndex(Predicate<T> match);

Predicate<T>类型是一个委托:

public delegate bool Predicate<T>(T obj);

其用法和Foreach()方法的Action委托类似。如果Predicate<T>委托返回true,就表示有一个匹配元素。如果返回false,表示没找到,继续搜素。

FindIndex(),FindLastIndex()方法返回找到的匹配元素的一个索引;Find(),FindLast()返回这个匹配的元素。

如果要获得与Predicate<T>匹配的所有项而不是一项,可以使用FindAll()方法。FindAll()方法的用法一样。FindAll()方法找到第一项后不会停止,而是继续迭代集合中的每一项:

List<Racer> l = racers.FindAll(r => r.Wins > 20);

7.排序

List<T>类可以使用Sort()方法对集合中的元素排序。Sort()方法使用快排算法排序。

Sort()方法有多个重载的方法。可以传递泛型委托Comparison<T>和泛型接口IComparer<T>,以及一个范围值和泛型接口IComparer<T>:

  public void List<T>.Sort();
  public void List<T>.Sort(Comparison<T>);
  public void List<T>.Sort(IComparer<T>);
  public void List<T>.Sort(Int32,Int32,IComparer<T>);

只有集合中的元素实现了IComparable接口,才能使用不带参数的Sort()方法。

使用public void List<T>.Sort(IComparer<T>); 需要定义一个实现了IComparer<T>接口的类,调用Sort(IComparer<T>)方法时会调用实现了IComparer<T>接口的类中的Compare方法:

      public class RacerComparer : IComparer<Racer>
          {
             public enum CompareType
              {
                FirstName,
                LastName,
                Country,
                Wins
              }
            private CompareType compareType;
            public RacerComparer(CompareType compareType)
            {
              this.compareType = compareType;
            }

            public int Compare(Racer x, Racer y)
            {
              if (x == null && y == null) return 0;
              if (x == null) return -1;
              if (y == null) return 1;

              int result;
              switch (compareType)
              {
                case CompareType.FirstName:
                  return string.Compare(x.FirstName, y.FirstName);
                case CompareType.LastName:
                  return string.Compare(x.LastName, y.LastName);
                case CompareType.Country:
                  result = string.Compare(x.Country, y.Country);
                  if (result == 0)
                    return string.Compare(x.LastName, y.LastName);
                  else
                    return result;
                case CompareType.Wins:
                  return x.Wins.CompareTo(y.Wins);
                default:
                  throw new ArgumentException("Invalid Compare Type");
              }
            }
          }

客户端代码:

   racers.Sort(new RacerComparer(RacerComparer.CompareType.Country));

使用public void List<T>.Sort(Comparison<T>); 需要一个Comparison<T>委托。Comparison<T>委托:public delagate int Comparsion<T>(int x,int y);

客户端代码:

racers.Sort((r1,r2) => r2.Wins.CompareTo(r1.Wins));

使用Reverse()方法,可以逆转整个集合的顺序。

8.类型转换

使用List<T>类的ConvertAll<TOutput>()方法,可以把所以类型的集合转换位另一种类型。ConvertAll<TOutput>()方法使用Converte委托,Converte委托:public sealed delegate TOutput Converter<TInput,TOutput>(TInput from);

        //定义一个Person类
        public class Person
        {
            private string name;

            public Person(string name)
            {
                this.name = name;
            }

            public override string ToString()
            {
                return name;
            }
        }

客户端代码:

  List<Person> persons =
  racers.ConvertAll<Person>(
    r => new Person(r.FiastName+" " + r.LastName)
  );

9.只读集合

创建集合后,它们就是可读写的。但是,在填充集合后,可以使用AsReadOnly()方法创建只读集合。

  List<Racer> racers2 =racers.AsReadOnly();

到此这篇关于C#集合之列表的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#集合之链表的用法

    LinkedList<T>是一个双向链表,其元素会指向它前面和后面的元素.这样,通过移动到下一个元素可以正向遍历链表,通过移动到前一个元素可以反向遍历链表. 链表在存储元素时,不仅要存储元素的值,还必须存储每个元素的下一个元素和上一个元素的信息.这就是LinkedList<T>包含LinkedListNode<T>类型的元素的原因.使用LinkedListNode<T>,可以获得列表中的下一个和上一个元素.LinkedListNode<T>定义了

  • C#集合之队列的用法

    队列是其元素按照先进先出(FIFO)的方式来处理的集合.队列使用System.Collections.Generic名称空间中的泛型类Queue<T>实现.在内部,Queue<T>类使用T类型的数组,这类似List<T>(https://www.jb51.net/article/244084.htm)类型.队列实现ICollection和IEnumerable<T>接口,但没有实现ICollection<T>接口,所以ICollection<

  • C#集合之有序列表的用法

    如果需要基于键对所需集合排序,就可以使用SortedList<TKey,TValue>类.这个类按照键给元素排序.这个集合中的值和键都可以使用任何类型.定义为键的自定义类型需要实现IComparer<T>接口,用于给列表中的元素排序.使用构造函数创建一个有序列表,在用Add方法添加: var books = new SortedList<string, string>(); books.Add("Professional WPF Programming&quo

  • C#集合之栈的用法

    栈(Stack)和队列是非常类似的一个容器,只是栈是一个后进先出(LIFO)的容器.栈用Push()方法在栈中添加元素,用Pop()方法获取最近添加的一个元素: Stack<T>与Queue<T>类(https://www.jb51.net/article/244090.htm)类似,实现了ICollection和IEnumerable<T>接口.Stack<T>类的成员: 在foreach语句中,栈的枚举器不会删除元素,它只会逐个返回元素.使用Pop()方

  • C#集合之集(set)的用法

    包含不重复元素的集合称为“集(set)”..NET Framework包含两个集HashSet<T>和SortedSet<T>,它们都实现ISet<T>接口.HashSet<T>集包含不重复元素的无序列表,SortedSet<T>集包含不重复元素的有序列表.ISet<T>接口提供的方法可以创建合集,交集,或者给出一个是另一个集的超集或子集的信息. var companyTeams = new HashSet<string>

  • C#集合之列表的用法

    目录 1.创建列表 2.添加元素 3.插入元素 4.访问元素 5.删除元素 6.搜索 7.排序 8.类型转换 9.只读集合 .NET Framework为动态列表List提供泛型类List<T>.这个类实现了IList,ICollection,IEnumerable,IList<T>,ICollection<T>,IEnumerable<T>接口. 1.创建列表 创建一个赛车手类,下面的例子会用到: public class Racer : ICompara

  • Python字典生成式、集合生成式、生成器用法实例分析

    本文实例讲述了Python字典生成式.集合生成式.生成器用法.分享给大家供大家参考,具体如下: 字典生成式: 跟列表生成式一样,字典生成式用来快速生成字典,不同的是,字典需要两个值 #d = {key: value for (key, value) in iterable} d1 = {'x': 1, 'y': 2, 'z': 3} d2 = {k: v for (k, v) in d1.items()} print(d2) 集合生成式: 集合生成式格式和列表生成式类似,不过用的是大括号: s1

  • Android列表对话框用法实例分析

    本文实例讲述了Android列表对话框用法.分享给大家供大家参考.具体如下: main.xml布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:la

  • Python列表切片用法示例

    本文实例讲述了Python列表切片用法.分享给大家供大家参考,具体如下: Python中符合序列的有序序列都支持切片(slice),例如列表,字符串,元组. 格式:[start:end:step] start:起始索引,从0开始,-1表示结束 end:结束索引 step:步长,end-start,步长为正时,从左向右取值.步长为负时,反向取值 注意切片的结果不包含结束索引,即不包含最后的一位,-1代表列表的最后一个位置索引 a=[1,2,3,4,5,6] b1=a[:] #省略全部,代表截取全部

  • java集合中list的用法代码示例

    List接口是Collection接口的子接口,List有一个重要的实现类--ArrayList类,List中的元素是有序排列的而且可重复,所以被称为是序列. List可以精确的控制每个元素的插入位置,或删除某个位置元素,它的实现类ArrayList底层是由数组实现的. List中有增删改查的方法,我们可以通过例子演示: 我们通过对学生选课,来演示List中对课程增删改查的方法 /** * 课程类 * @author lenovo * */ public class KeCheng { publ

  • React Native中ScrollView组件轮播图与ListView渲染列表组件用法实例分析

    本文实例讲述了React Native中ScrollView组件轮播图与ListView渲染列表组件用法.分享给大家供大家参考,具体如下: 1.Scroll View ScrollView是React Native提供的滚动视图组件,渲染一组视图,用户可以进行滑动响应交互,其常用属性如下: 滚动的偏移量:通过event.nativeEvent.contentOffset.x可以得到水平偏移量. horizontal={bool},属性为true时,所有子视图在水平方向排列,否则在纵向排列.默认为

  • python 字典和列表嵌套用法详解

    python中字典和列表的使用,在数据处理中应该是最常用的,这两个熟练后基本可以应付大部分场景了.不过网上的基础教程只告诉你列表.字典是什么,如何使用,很少做组合说明. 刚好工作中采集prometheus监控接口并做数据处理的时候,用了很多组合场景,列出几个做一些分享. 列表(List) 序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. 列表是最常用的Python数据类型,它可以作为一个方括号内的逗号分隔值出现

  • Python元素集合的列表切片

    目录 一.列表切片(Slicing) 二.基础实例 三.带有负索引的切片(SlicewithNegativeIndices) 四.带有正负索引的切片 五.指定切片step 六.负步长 七.在开始和结束处切片(SliceatBeginning&End) 八.反转列表(ReverseaList) 九.修改多个列表元素值 十.插入多个列表元素 十一.删除多个列表元素 十二.克隆或复制列表 一.列表切片(Slicing) 由于列表是元素的集合,我们应该能够获得这些元素的任何子集. 例如,如果想从列表中获

  • C++深入讲解初始化列表的用法

    目录 一.小问题 二.类成员的初始化 三.类中的 const 成员 四.初始化与赋值的不同 五.小结 一.小问题 下面的类定义是否合法? 如果合法,ci 的值是什么,存储在哪里? 下面编写代码一探究竟(代码1): #include <stdio.h> class Test { private: const int ci; public: Test() { ci = 10; } int getCI() { return ci; } }; int main() { Test t; printf(&

随机推荐