【C#】List.ForEach方法
List.ForEach方法
- List.ForEach方法
- MSDN 文档
- 回到修改主题
- C#中foreach和list.ForEach的区别
- 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
- List 常用属性
- 参考文章
List.ForEach方法
今天冯同学在研究DataTable更新数据时,传统做法遍历DataTable(很多人可能会说为何还用DT,历史原因不做探讨)。不过也说明了如果是List就可以利用lambda表达式处理。后来冯神就提到ForEach可以精简代码。那我们就来学习下List.ForEach方法吧。
DataTable 转List:
var var_dtTable = dtTable.AsEnumerable().toList();
简单介绍:
Lamdba是延迟执行的,实际上什么都没有发生,当真正使用对象的时候(例如调用:First, Single, ToList….的时候)才执行。
- Where语句使用
var var_dtTable = dtTable.AsEnumerable().Where<DataRow>(W => W["NAME"].ToString()=="张三");
int count = var_dtTable.Count<DataRow>();//获取dtTable中NAME为张三的个数
- Average语句使用
int avg = dtTable.AsEnumerable().Average<DataRow>(A => float.Parse(A["avg_name"].ToString()))
//获取dtTable中avg_name列的平局数
- 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列的顺序
- OrderBy
DataTable dtTable = new DataTable();//数据源
dtTable = dtTable.AsEnumerable().OrderByDescending(o => o["OrderBy_name"]).CopyToDataTable();//降序
dtTable = dtTable.AsEnumerable().OrderBy(o => o["OrderBy_name"]).CopyToDataTable();//升序
- 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的区别
- 在foreach和list.ForEach中使用list.Remove()
- 在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()的使用