【类库】容器对象(List、DataTable、 DataView、Dictionary)

  首先申明一下,写此博文的目的是纪录一下,知识都是现成的,只是整理一下,为了让自己更容易看懂,比在其他地方更容易明白。因为它们太常用了,不忍心每次都去用那么长的时间查看MSDN,希望能在这里用理少的时间来理解并运用其用法。最终目标是减少从接触到能理解并使用的时间。

 List<T>类型的查找操作Find与FindIndex

 

             Point pt;
             List<Point> lstPs = new List<Point>();
             for (int i = 0; i < 10; i++)
             {
                 pt = new Point(i, i + 100);
                 lstPs.Add(pt);
             }
             Point pp = lstPs.Find( delegate(Point p)//pp是结果Point,是查到的目标
             {
                 return p.X == 9;//这个是有目标的情况,如果没有这个X==9的这个点呢?
             });
             Point ppNo = lstPs.Find(delegate(Point p)
             {
                 return p.X == 1000;//如果队列中没有目标点,返回的是Point类型的默认值
             });
             Console.WriteLine("目标点是:"+pp);
             Console.WriteLine("没有发现目标点时得到的是默认值:" + ppNo);
             /*
              返回结果如下:
               目标点是:{X=9,Y=109}
               没有发现目标点时得到的是默认值:{X=0,Y=0}
              */
List过滤

   结论:使用Find方法时要注意return 语句后面是bool类型的表达式,不是想当然的返回一个目标T类型,这里是Point类型。在List中有目标就查到目标,如果没有话就返回 T类型的默认值(default(T)可得到)。

  FindIndex:

    //名字 值 单位组合  nvu
    struct NameValueUnit
    {
        public string oname;
        public string ovalue;
        public string ounit;
    }
        //移除一个组合 
        public void RemoveByName(string name)
        {
            int index = -1;
            index = lstNVU.FindIndex(delegate(NameValueUnit nvu)
            {
                if (nvu.oname.Equals(name))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            });
            lstNVU.RemoveAt(index);
        }
FindIndex的使用

 下面来看看FindAll的源码:

        public List<T> FindAll(Predicate<T> match) { 
            if( match == null) {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
            }
            Contract.EndContractBlock();

            List<T> list = new List<T>(); 
            for(int i = 0 ; i < _size; i++) {
                if(match(_items[i])) {
                    list.Add(_items[i]);
                }
            }
            return list;
        }
FindAll

主要依赖Predicate委托,那看一下这个委托:

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

传入一个用于判断满足条件的委托实例,就可以得到目标数据。很巧妙!

List查询最近值

//List获取最近值原理。
//从List中寻找离number最近的数
list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-number) ? x : y);
//从源码上看是遍历所有元素,时间复杂度是O(n);
最近值

 

 DataTable的使用

   1、添加列

  2、添加行

  3、查找数据select方法的使用

  4、获取列名

 

            DataTable dtAll = new DataTable();

            //下面建立列过程:分别添加名为ID的列,名为name的列,名为score的列,类型分别是long,string,float。
            DataColumn dc = new DataColumn("ID", typeof(long));
            dtAll.Columns.Add(dc);
            dc = new DataColumn("name", typeof(string));
            dtAll.Columns.Add(dc);
            dc = new DataColumn("score", typeof(float));
            dtAll.Columns.Add(dc);
            //为表添加行
            DataRow dr = dtAll.NewRow();
            dr[0] = 2009000;//其实是一个装箱过程,把int装箱为object
            dr[1] = "john";
            dr[2] = 98.5;
            dtAll.Rows.Add(dr);

            dr = dtAll.NewRow();
            dr[0] = 2009001;
            dr[1] = "Lucy";
            dr[2] = 23.5;
            dtAll.Rows.Add(dr);
            DataRow[] drs = dtAll.Select("ID=2009000");
            Console.WriteLine(drs[0][2]);//查找到的第一个人的分数score,结果是当然的98.5
添加行和列

  几个需要注意的地方。第一、先添加列,而不是先添加行,在添加列后再补充每行;第二、向第n行的第m列添加数据时是一个装箱过程,取出目标数据时需要拆箱操作,一般是Convert.To***方法;第三、查寻时的过滤条件是string,语法是SQL相仿。

  一个例子:查找条件不同时的结果。

             DataTable dt = new DataTable();
             for (int i = 0; i < 2; i++)//加两列
             {
                 DataColumn dc = new DataColumn();
                 if (i == 0)
                 {
                     dc.ColumnName = "we";
                     dc.DataType = typeof(int);
                 }
                 dt.Columns.Add(dc);
             }
 
             DataRow dr = dt.NewRow();
             dr[0] = 99;
             dr[1] = "ddd";
             dt.Rows.Add(dr);
 
             dr = dt.NewRow();
             dr[0] = 80;
             dr[1] = "808080";
             dt.Rows.Add(dr);
 
             string condition = "we>70 and we<" + 90;
             DataRow[] drs = dt.Select(condition);
             string tmp = drs[0][1].ToString();//能输出正常结果,根据条件condition的不同输出不同的结果
             Console.WriteLine(tmp);
Select条件查找的使用

  condition作为条件,使用SQL语法 .

  要获取列名只用一条语句 :

   1 dataTable.Columns[i].ColumnName;//得到第i列的列名

5、复制表结构

DataTable dt2 = dt1.Clone();//这样把表dt1的结构复制到表dt2中,但是不复制数据

6、得到DataTable的第begin行到第end行的数据,并返回一个过滤后的DataTable

/// <summary>
        /// 过滤第begin行到到end行之间的数据行
        /// </summary>
        /// <param name="begin">开始行</param>
        /// <param name="end">结束行</param>
        /// <param name="oDT">源表</param>
        /// <returns></returns>
        public static DataTable DtSelectRows(int begin,int end, DataTable oDT)
        {

            if (oDT.Rows.Count < end) return oDT;
            DataTable NewTable = oDT.Clone();
            DataRow[] rows = oDT.Select("1=1");
            for (int i = begin; i <=end; i++)
            {
                NewTable.ImportRow((DataRow)rows[i]);
            }
            return NewTable;
        }
过滤第begin行到到end行之间的数据行

 交换两行

        public static DataTable SwapRow(int index1, int index2, DataTable dt)
        {
            DataRow dr = dt.NewRow();
            dr.ItemArray = dt.Rows[index1].ItemArray;
            dt.Rows[index1].ItemArray = dt.Rows[index2].ItemArray;
            dt.Rows[index2].ItemArray = dr.ItemArray;
            return dt;
        }
交换两行

 DataView的一些用法

   1、使用DataTable得到DataView时一个问题

  原始有问题的代码如下:

1             DataView dvClass = booksClass.dtClass.DefaultView;
2             DataView dvChild = booksClass.dtClass.DefaultView;
3             dvClass.RowFilter="father='11'";
4             dvChild.RowFilter = "father='22'";

  这样做后,回头再看发现dvClass 和 dvChild的RowFilter是相同的,都是"father='22'";原来是因为dvClass dvChild引用了同一个实例。所以修改如下:

1             DataView dvChild = new DataView(booksClass.dtClass);// booksClass.dtClass.DefaultView;
2             dvClass.RowFilter = "father='11'";
3             dvChild.RowFilter = "father='222'";

  问题得以解决,两个DataView就变得独立了。

 List的排序

 

  private void InitSS()
         {
             List<MyStruct> lstStructs = new List<MyStruct>();
 
             MyStruct ms1, ms2, ms3, ms4;
             ms1.age = 11;
             ms1.name = "aa";
             lstStructs.Add(ms1);
 
             ms2.age = 23;
             ms2.name = "bb";
             lstStructs.Add(ms2);
 
             ms3.age = 32;
             ms3.name = "dd";
             lstStructs.Add(ms3);
 
             ms4.age = 4;
             ms4.name = "ss";
             lstStructs.Add(ms4);
 
             textBox1.Text = string.Empty;
 
             textBox1.Text += "排序前:
";
             foreach (var item in lstStructs)
             {
                 //Console.WriteLine(item.Id + "," + item.Name);
                 textBox1.Text += item.age + ":" + item.name + "
";
             }
 
             lstStructs.Sort(delegate(MyStruct info1, MyStruct info2)
                         {
                             return info1.age.CompareTo(info2.age);//排序的关键
                         });
             //Console.WriteLine("*****ListSort**********");
             textBox1.Text += "排序后:
";
             foreach (var item in lstStructs)
             {
                 //Console.WriteLine(item.Id + "," + item.Name);
                 textBox1.Text += item.age + ":" + item.name + "
";
             }
         }
 
         private void btnSsort_Click(object sender, EventArgs e)
         {
             InitSS();
         }
     }
 
     struct MyStruct
     {
         public int age;
         public string name;
     }
排序示例

5、复制表结构

 Dictionary

1、根据value得到key

1 var firstKey = dic.FirstOrDefault(q => q.Value == "2").Key;  //get first key  其中q为一个键值对

 两个List<>互相过滤数据

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AboutList
{
    class Program
    {
        static void Main(string[] args)
        {
            Student s1 = new Student { Age=10,Name="deng"};
            Student s2 = new Student { Age = 15, Name = "li" };
            Student s3 = new Student { Age = 18, Name = "" };
            Student s4 = new Student { Age = 20, Name = "" };
            Student s5 = new Student { Age = 25, Name = "" };
            List<Student> list1 = new List<Student> { s1, s2, s3, s4, s5 };
            List<Student> list2 = new List<Student> { s1,s2};
            //下面查找不在list2中,只在list1中的Student实例
            List<Student> listRes = list1.FindAll(delegate(Student s) 
            {
                int index = list2.FindIndex(delegate(Student ss)
                {
                    return ss == s;
                });
                if (index >= 0)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            });
            //输出看结果
            foreach (var s in listRes)
            {
                Console.WriteLine("Name=" + s.Name + ";  Age=" + s.Age);
            }

            Console.Read();
        }
    }

    class Student
    {
        public int Age
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }
    }
}
View Code

 List删除 重复数据

    // 不能用foreach,因为迭代器是只读的
    for (int i = 0; i < strs.Count; i++)
    {
        // 如果第一次出现的位置不等于最后一次出现的位置,则说明该元素不止出现一次
        if (strs.IndexOf(strs[i]) != strs.LastIndexOf(strs[i]))
        {
            strs.RemoveAt(strs.LastIndexOf(strs[i]));
        }
    }
删除重复

 

ddd

 

ddd

 

ddd

 

ddd

 

ddd

 

ddd

原文地址:https://www.cnblogs.com/ddx-deng/p/3773077.html