List.ForEach方法

今天冯同学在研究DataTable更新数据时,传统做法遍历DataTable(很多人可能会说为何还用DT,历史原因不做探讨)。不过也说明了如果是List就可以利用lambda表达式处理。后来冯神就提到ForEach可以精简代码。那我们就来学习下List.ForEach方法吧。
DataTable 转List:
var var_dtTable = dtTable.AsEnumerable().toList();
简单介绍:
Lamdba是延迟执行的,实际上什么都没有发生,当真正使用对象的时候(例如调用:First, Single, ToList….的时候)才执行。

  1. Where语句使用
var var_dtTable = dtTable.AsEnumerable().Where<DataRow>(W => W["NAME"].ToString()=="张三");
int count = var_dtTable.Count<DataRow>();//获取dtTable中NAME为张三的个数
  1. Average语句使用
int avg = dtTable.AsEnumerable().Average<DataRow>(A => float.Parse(A["avg_name"].ToString()))
//获取dtTable中avg_name列的平局数
  1. GroupBy
DataTable dtTable = new DataTable();//数据源
DataTable dtResult = new DataTable();
dtResult.Columns.Add("groupBy_name", typeof(string));
dtResult.Columns.Add("sum_name", typeof(int));
dtResult.Columns.Add("count_name", typeof(int));
var var_dtTable= dtTable.AsEnumerable().GroupBy(G => G["groupBy_name"].ToString()).Select(S => new {
               groupBy_name= s.Key,//获取分组的值
               sum_name= s.Sum(m => m.Field<int>("sum_name")),//获取列名为sum_name数据的和
               count_name= s.Count(m => m.Field<int>("count_name"))//获取列名为count_name数据的个数
               });
var_dtTable.ToList().ForEach(f=> dtResult.Rows.Add(f.groupBy_name,f.sum_name,f.count_name);
//对应的顺序为dtResult列的顺序
  1. OrderBy
DataTable dtTable = new DataTable();//数据源
dtTable = dtTable.AsEnumerable().OrderByDescending(o => o["OrderBy_name"]).CopyToDataTable();//降序
dtTable = dtTable.AsEnumerable().OrderBy(o => o["OrderBy_name"]).CopyToDataTable();//升序
  1. Distinct
DataTable dtTable = new DataTable();//数据源
dtTable = dtTable.AsEnumerable().Distinct(new ColumnEquals("column_name")).CopyToDataTable();
//column_name是要Distinct列的名字

MSDN 文档

定义
命名空间:
System.Collections.Generic
程序集:
System.Collections.dll
对 List 的每个元素执行指定操作。

public void ForEach (Action<T> action);

参数
action
Action
要对 List 的每个元素执行的 Action 委托。

List<string> names = new List<string>();
names.Add("Bruce");
names.Add("Alfred");
names.Add("Tim");
names.Add("Richard");

// Display the contents of the list using the Print method.
names.ForEach(Print);

// The following demonstrates the anonymous method feature of C#
// to display the contents of the list to the console.
names.ForEach(delegate(string name)
{
    Console.WriteLine(name);
});

void Print(string s)
{
    Console.WriteLine(s);
}

/* This code will produce output similar to the following:
* Bruce
* Alfred
* Tim
* Richard
* Bruce
* Alfred
* Tim
* Richard
*/

居然可以调用委托函数,这个简直太方便了。
比如是一个邮件列表:可以在委托方法中推送邮件。当然传统遍历也是可以的。
代码显得优雅,简洁了。

回到修改主题

通常我们对符合条件的List进行部分更新。lambda表达式where关键字处理即可。

//1.Where条件过滤
list.Where(a =>string.IsNullOrWhiteSpace(a.Id) && (!a.Called || (a.Called && _checkCalled.Checked))).ToList();
//2.相当于SQL语句 select * from Study where Stuid in (1,5);
list= list.Where(a => "1,5".Contains(a.Stuid)).ToList();

//List.Foreach
//1.指定某条数据 Check为true,箭头函数=>简化
 list.ForEach((itm) =>
                   {
                     if (txtOsaCbiMemolst.Tag.ToString().Contains(itm.BiId))
                        {
                          itm.Check = true;
                        }
                    });
 //2.全部为true 
   list.ForEach(m=>m.Check = true);


是不是很方便呢?

C#中foreach和list.ForEach的区别

  1. 在foreach和list.ForEach中使用list.Remove()
  2. 在foreach中是不能使用list.Remove(),否则在进入下一个循环就会报异常,所以,如果有使用之后就必须break;

在.ForEach()中,要注意,在.net framework 4.5 会报异常:集合已修改;可能无法执行枚举操作。在.net framework4 3.5 3.0 2.0这几个版本下,可以直接使用list.Remove(),但如果在使用Remove()后下一项是不会遍历到,会自动用下下项。如下代码:

List<Person> list = new List<Person>(){
                new Person(){ Id=1,Name="1"},
                new Person(){ Id=2,Name="2"},
                new Person(){ Id=3,Name="3"},
                new Person(){ Id=4,Name="4"},
            };
            list.ForEach(item =>
            {
                Console.WriteLine(string.Format("111--Id:{0},Name:{1}", item.Id, item.Name));
                if (item.Id == 2)
                {
                    list.Remove(item);
                    item.Id = item.Id * 10;
                }
                item.Id = item.Id * 10;
                Console.WriteLine(string.Format("222--Id:{0},Name:{1}", item.Id, item.Name));
            });
            Console.WriteLine("------------");
            list.ForEach(item => Console.WriteLine(string.Format("Id:{0},Name:{1}", item.Id, item.Name)));

结果:

111–Id:1,Name:1
222–Id:10,Name:1
111–Id:2,Name:2
222–Id:200,Name:2
111–Id:4,Name:4
222–Id:40,Name:4

Id:10,Name:1
Id:3,Name:3
Id:40,Name:4

就是在id=2这项remove后还会对这项进行操作,但在进入下一项是id=4,而id=3这项没有遍历到
所以如果想删除id=2和id=3这两项,结果是id=3是删除不了,如下:

list.ForEach(item =>
            {
                if (item.Id == 2 || item.Id==3)
                {
                    list.Remove(item);
                }
            });
list.ForEach(item => Console.WriteLine(string.Format("Id:{0},Name:{1}", item.Id, item.Name)));

结果:

Id:1,Name:1
Id:3,Name:3
Id:4,Name:4

只删除了id=2这项,所以想删除list中的项,最好还是用for

for (int i = 0; i < list.Count; i++)
{
	if (list[i].Id == 2 || list[i].Id == 3)
    	{
        	list.Remove(list[i]);
            i--;
        }
}

注意删除后,i–;

或者使用list.RemoveAll(),如下:

list.RemoveAll(item => { return item.Id == 2 || item.Id == 3; });
list.ForEach(item => Console.WriteLine(string.Format("Id:{0},Name:{1}", item.Id, item.Name)));

所以,想删除list中的项,最好不用使用foreach和list.ForEach,而是使用for或list.RemoveAll

2. 在list.ForEach()中不能使用continue或者break

如果在遍历到某个特殊项的时候,不用遍历后面的项,需要break,这种情况使用foreach

3.list.ForEach()的使用
见上文MSDN说明

List 常用属性

List的方法和属性 方法或属性 作用

Capacity 用于获取或设置List可容纳元素的数量。当数量超过容量时,这个值会自动增长。您可以设置这个值以减少容量,也可以调用trin()方法来减少容量以适合实际的元素数目。

Count 属性,用于获取数组中当前元素数量

Item( ) 通过指定索引获取或设置元素。对于List类来说,它是一个索引器。

Add( ) 在List中添加一个对象的公有方法

AddRange( ) 公有方法,在List尾部添加实现了ICollection接口的多个元素

BinarySearch( ) 重载的公有方法,用于在排序的List内使用二分查找来定位指定元素.

Clear( ) 在List内移除所有元素

Contains( ) 测试一个元素是否在List内

CopyTo( ) 重载的公有方法,把一个List拷贝到一维数组内

Exists( ) 测试一个元素是否在List内

Find( ) 查找并返回List内的出现的第一个匹配元素

FindAll( ) 查找并返回List内的所有匹配元素

GetEnumerator( ) 重载的公有方法,返回一个用于迭代List的枚举器

Getrange( ) 拷贝指定范围的元素到新的List内

IndexOf( ) 重载的公有方法,查找并返回每一个匹配元素的索引

Insert( ) 在List内插入一个元素

InsertRange( ) 在List内插入一组元素

LastIndexOf( ) 重载的公有方法,,查找并返回最后一个匹配元素的索引

Remove( ) 移除与指定元素匹配的第一个元素

RemoveAt( ) 移除指定索引的元素

RemoveRange( ) 移除指定范围的元素

Reverse( ) 反转List内元素的顺序

Sort( ) 对List内的元素进行排序

ToArray( ) 把List内的元素拷贝到一个新的数组内

trimToSize( ) 将容量设置为List中元素的实际数目

参考文章

[1]: MSDN
[2]: C#中foreach和list.ForEach的区别
[3]: Lamdba及DataTable AsEnumerable()的使用

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐