当前位置:   article > 正文

杂七杂八——使用LINQ检索重复值_wpf linq检索

wpf linq检索

杂七杂八——使用LINQ检索重复值

 

日常工作的时候,我们经常遇到需要检索一组数据中是否有重复值的情况,再根据具体情况进行相应的操作。如果不使用LINQ,那我们就得使用一层一层的foreach循环来做,不但麻烦、工作效率低(因为你得绕啊~~绕啊~~~),而且容易出bug。使用LINQ就方便得多。

 

举个我前天在工作中遇到的例子吧。当时是这样的——我需要查看一下用户新插入的值是否已经存在于数据库当中,如果有,就提醒客户不能插入这个值(实际上这个值是PK)。因为在进入页面的时候,我已经把目前数据库里所有的值都读出来、放在一个DataTable里了,所以在用户保存的时候,我没必要连接数据库进行查询,只需要检索当前这个DataTable就OK了。

 

假设这个DataTable有3列,分别是ID、Name、Age,ID是PK。使用foreach的笨办法,是这样:

 

  1. foreach (DataRow r1 in table.Rows){    foreach (DataRow r2 in table.Rows)    {        if (r2 != r1 && r2["ID"].ToString() == r1["ID"].ToString())        {            Console.WriteLine("Warning!");            return false// 检验失败         }    }}

如果写成这样,需要注意两点:

  • 必需要有r2 != r1这个条件,不然当一个DataRow“自己遇到自己”的时候,无论如何都会return false的
  • 必需把r1["ID"]和r2["ID"]转换成string(如果你确定它是int,那转成int也行)再进行比较,不然r1["ID"]和r2["ID"]是两个object,调用==操作符,比较的是这两个对象是否是同一个对象——当然不是!所以,永远也不会return false

上面这种笨办法适用于两种情况:

  1. 需要比较简单、只要有重复值立刻撤退的情况
  2. 公司把代码行数与程序工资挂钩的情况

使用LINQ可以更简单地完成上面的任务,而且还可以衍生出很多附加功能:

 

我们把需求稍微改动一下,改成检验Age有没有重复的,如果有、每个值有几个重复。如果用foreach循环,那我们就要在循环内部加上一个Dictionay,以Age为Key,并对每个Key进行计数了。

 

使用LINQ中的GroupBy操作,就能轻松解决这个问题。源码如下:

 

  1. // 水之真谛 // http://blog.csdn.net/FantasiaX using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data;namespace ConsoleApplication1{    class Program    {        static void Main(string[] args)        {            DataTable table = new DataTable();            table.Columns.Add(new DataColumn("ID", typeof(int)));            table.Columns.Add(new DataColumn("Name", typeof(string)));            table.Columns.Add(new DataColumn("Age", typeof(int)));            int[] ids = new int[] { 123456 };            string[] names = new string[] { "Tim""Yan""Xiao Chen""Miao""Big Ma""Little Ma" };            int[] ages = new int[] { 282428222722 };            for (int i = 0; i < 6; i++)            {                DataRow row = table.NewRow();                row["ID"= ids[i];                row["Name"= names[i];                row["Age"= ages[i];                table.Rows.Add(row);            }            // 使用foreach             Dictionary<int, int> dic = new Dictionary<int, int>();            foreach (DataRow row in table.Rows)            {                if (!dic.Keys.Contains(Convert.ToInt32(row["Age"])))                {                    dic.Add(Convert.ToInt32(row["Age"]), 1);                }                else                {                    dic[Convert.ToInt32(row["Age"])]++;                }            }            foreach (var item in dic)            {                Console.WriteLine("{0}, {1}", item.Key, item.Value);            }            Console.WriteLine("=========================================");            // 使用LINQ (隐式数据类型)             var ageGroups = table.Rows.Cast<DataRow>().GroupBy(row => Convert.ToInt32(row["Age"]));            foreach (var group in ageGroups)            {                Console.WriteLine("{0}, {1}"group.Key.ToString(), group.Count().ToString());            }            Console.WriteLine("=========================================");            // 使用LINQ (显式数据类型)             IEnumerable<IGrouping<int, DataRow>> ageGroups2 = table.Rows.Cast<DataRow>().GroupBy(row => Convert.ToInt32(row["Age"]));            foreach (IGrouping<int, DataRow> group in ageGroups2)            {                Console.WriteLine("{0}, {1}", group.Key.ToString(), group.Count().ToString());            }            Console.WriteLine("=========================================");            // 很酷的写法             var ageGroups3 = from row in table.Rows.Cast<DataRow>() group row by Convert.ToInt32(row["Age"]) into resultCollection select resultCollection;            foreach (var group in ageGroups3)            {                Console.WriteLine("{0}, {1}", group.Key.ToString(), group.Count().ToString());            }            Console.WriteLine("=========================================");            // 比较BT的写法             foreach (var group in from row in table.Rows.Cast<DataRow>() group row by Convert.ToInt32(row["Age"]) into resultCollection select resultCollection)            {                Console.WriteLine("{0}, {1}", group.Key.ToString(), group.Count().ToString());            }        }    }}

其中最核心的一句是:var ageGroups = table.Rows.Cast<DataRow>().GroupBy(row => Convert.ToInt32(row["Age"]));

意思是告诉LINQ解析器说“请以Convert.ToInt32(row["Age"])为Key,对row们进行分组,并把这些组放在名为ageGroups的集合中去”。为了不让程序记忆太多的数据类型,C# 3.0提供了var隐式数据类型语法——程序员可以不知道是什么类型、但编译器对类型却清清楚楚。实际上,GroupBy()操作后的结果是一个以IGrouping<int, DataRow> 为元素的IEnumerable<IGrouping<int, DataRow>> 集合。

 

因为GroupBy()操作正好对应有LINQ关键字,所以才有最近两种改写。并不是每个LINQ操作都有对应的LINQ关键字,不知道C# 4.0会不会有所扩展。

 

BTW,因为LINQ操作只能应用在可枚举的集合类型上,而DataTable.Rows集合是个普通集合、不具有可枚举性,所以需要Cast一下。

 

如果这时候客户的需求再改成:列出Age相同的人的Name,那么使用foreach循环的复杂度就有点儿失控了(估计程序员的情绪也比较失控)……而使用LINQ则只需要对每个group进行一下枚举。

 

LINQ语法适合与以下两种情况:

  • 懒人,就像我一样
  • 工资与效率挂钩

OVER

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/134854?site
推荐阅读
相关标签
  

闽ICP备14008679号