LINQ 学习笔记(1)

2018-06-17 19:53:18来源:未知 阅读 ()

新老客户大回馈,云服务器低至5折

学习资源参考 : http://www.cnblogs.com/lifepoem/archive/2011/12/16/2288017.html

 

常用方法是 Where, OrderBy, Select 

高级点的是 GroupBy, Join

 

LINQ 主要用于解决早期多种数据类型之间的交互关系,还有forloop的场景,比如以前我们总觉得 List<Class> 不就是table 嘛,干嘛要搞分类强转,不能学一下js吗。过后我们就自己用泛类,反射和委托等等实现了一些方便处理不同数据格式的问题(基本上有点像js了)。后来微软就统一大家的方式,写出了完整的LINQ啦,LINQ后来的发展很好,还用来做LINQ TO SQL 在不需要写SQL 语句下也能做好 CRUD 操作,现在是在 entity framework 下。

 

虽然如此强大,不过这里只是记入一些入门篇而已。而且本文只作为个人复习而已,如果在下理解有误请高手给予纠正。新手嘛请远离,以免我误人子弟,哈哈.

思想: 我觉得实现原理依然是用了反射,委托,泛类,调用的逻辑基本上和js差不多, 就是封装了forloop,然后让你传一个function进来操作每个row进行修改过滤等等。只是语法用解析器调整了一下,变得容易看容易写。

 

下面是一些基本的使用和解释,都是用代码呈现。

where 的重点就是内部是一个表达式,结果要是 true || false , true就保留,false就被过滤掉(解析时会运用到每一行上)
select 的用途是可以对结果在进行一次修改, 还可以返回新的对象 (解析是会运用到每一行上)
where和select()内n是一个参数,写m也行,这个参数代表了List里面的值,如果List里面是对象,那就是对象咯

上代码

   List<string> nameList = new List<string> { "keatkeat", "xinyao", "ahyou" };
            //我想过滤数据,保留字母长度 = 5 的,然后我希望把字便大写 
            //方法语法          
            IEnumerable<string> result1 = nameList
                                        .Where(n => n.Length == 5) 
                                        .Select(n => n.ToUpper());
            //查询语法
            var result = from name in nameList
                         where name.Length == 5
                         select name.ToUpper();                                             
            string json = stoogesV3.toJson(result); //["AHYOU"]

站在js的角度可以这样去理解

  function List(array) {
            this.array = array;
            this.whereList = [];
            this.selectFn;
        };
        List.prototype.where = function (fn) {
            this.whereList.push(fn); //把所有where语句加进去
            return this;
        };
        List.prototype.select = function (fn) {
            this.selectFn = fn; //只会有一个select语句
            return this;
        };
        List.prototype.toList = function () {
            var result = []; //这里偷懒,只返回普通数组
            var array = this.array;            
            for (var i = array.length - 1; i >= 0 ; i--) {
                var value = array[i];            
                var is_remove = this.whereList.some(function (fn) {
                    return (fn(value) === false); //只要一个false就remove     
                });
                if (is_remove) {
                    array.splice(i, 1);
                }
                else {
                    var finalValue = (this.selectFn) ? this.selectFn(value) : value; //用selectFn 修改最终的值
                    result.unshift(finalValue);
                }
            }
            return result;
        };

        var nameList = new List(["keatkeat", "xinyao", "ahyou"]);
        var result = nameList.where(function (n) {
            return n.length === 5;
        }).select(function (n) {
            return n.toUpperCase();
        }).toList();

        alert(result);

 

OrderBy 

            //用thenBy来连接
            List<Person> list = new List<Person> { 
                new Person{ name= "keatkeat", age= 18 },
                new Person{ name= "xinyao", age= 19 },
                new Person{ name= "ahyou", age= 17 },
                new Person{ name= "bhyou2", age= 17 },
                new Person{ name= "chyou2", age= 17 } 
            };
            var result = list.OrderBy(n => n.age).ThenByDescending(n => n.name);
         
            var result1 = from person in list
                          orderby person.age, person.name descending
                          select person;

            string json = stoogesV3.toJson(result1);

 

子查询 

注意,LINQ to Object 的子查询会在每次调用result的时候执行,所以优化的方法是提前把依赖的值装在变量,而不要一直运行子查询。

        string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
        //最好的做法其实是先拿出来 
        int shorter = names.Min(n => n.Length);
        var result = names.Where(n => n.Length == shorter);

        // 获取所有长度最短的名字(注意:可能有多个)
        var result1 = names.Where(n => n.Length == (names.Min(g => g.Length)));
        var result2 = from n in names
                     where n.Length == (from n2 in names orderby n2.Length select n2.Length).First()
                     select n;

 

LINQ 是后运行的,也就是说一般上当我们写好语句,在还没有调用result时(比如 toJson | foreach ), 他是不会执行的,一直等到我们调用才运行,当然凡事总有另外 !

下面就是一些会让语句直接执行的情况 

 

            int[] numbers = { 10, 9, 8, 7, 6 };
            int firstNumber = numbers.First();// 10
            int lastNumber = numbers.Last();// 6
            ClassA obj = array.FirstOrDefault(); //如果没有是null, int 是 0,base on 类型的default value
            int secondNumber = numbers.ElementAt(1);// 9
            int count = numbers.Count();// 5
            int min = numbers.Min(); // 6
            int max = numbers.Max();//10
            bool hasTheNumberNine = numbers.Contains(9); //true
            bool hasElements = numbers.Any();// true
            bool hasAnOddElement = numbers.Any(n => (n % 2) == 1);//true 只要其中一个比配到的 

 

 

concat vs union 

concat 就是把2个List combine 

union 也是combine 但是,union 会自动distict,过滤掉重复的数据, 它是combine之后一起全部distict哦. 

 

            int[] num1 = { 1, 2, 2, 3 };
            int[] num2 = { 3, 4, 5 };
            IEnumerable<int> concat = num1.Concat(num2);//[1,2,2,3,3,4,5]
            IEnumerable<int> union = num1.Union(num2);//[1,2,3,4,5]

 

ToList 

刚说LINQ是后执行,为了优化可以用 ToList() 把result装起来 , 但是记得他依然是引用不是clone哦

        List<user> user_list = new List<user> { new user { name = "xinyao", age = 5 }, new user { name = "keatkeat", age = 10 } };
        List<user> result = user_list.Where(n => n.name == "xinyao").ToList<user>(); //这里保存的是引用

 

常用的 filter 过滤器

        //skip 和 take 可以当场mysql 的 limit 5,50 就好象 skip 5 take 50
        string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
        var result = names.Take(3); //那前3个
        var result1 = names.Skip(3); //skip 头3个 
        var result2 = names.TakeWhile(n => n.Length > 2); //从条件之后才开始拿 
        var result3 = names.SkipWhile(n => n.Length > 2); //头开始 skip 直到条件之后拿
        var reuslt4 = names.Distinct(); //过滤掉多余重复的

 

寻找差异值

Except , 找出 enum1有而enum2没有的值集合,这里头的比较是使用引用==,也就是说如果指针不同就算值一样也算false不一样。

        List<string> a = new List<string> { "a", "b" };
        List<string> b = new List<string> { "a" };
        var result = a.Except(b); //这里用的是引用== ,也就是说不通指针值一样也算不一样  可以找出 a有而b没有的值        

 

接下来就是重头戏 GroupBy, Join 了

我们常因为SQL索引难以优化的情况下,利用多次select来取出table, 然后就可以利用join或者groupBy来代替sql的工作了。

 

GroupBy 思想

运行GroupBy查询之后,返回的是一个group集合, 想想看开始是一个table,你把row group起来后, 它就像是变成了多个table, 每个table分到了一部分的row 

所以在foreach result 的时候它每一条记入都是一个类似table的集合里面包含了group好的row .

GroupBy 变化较多,重点是明白思想 

             List<Product> products = new List<Product> { 
               new Product {code = "mk100",color = "red",size = "m"},
               new Product {code = "mk100",color = "red",size = "s"},
               new Product {code = "mk100",color = "yellow",size = "s"},
               new Product {code = "mk100",color = "yellow",size = "m"},
               new Product {code = "mk100",color = "yellow",size = "l"},
               new Product {code = "mk200",color = "red",size = "s"},
               new Product {code = "mk200",color = "red",size = "m"},
            };
           
            var result = products
                        .GroupBy(n => new { n.code, n.color })
                        .Select(n => new { code = n.First().code, color = n.First().color, size = String.Join(",", n.Select(m => m.size)) });
          //select 的时候不要重复的column可以直接获取第一个row的值就行了
string json = stoogesV3.toJson(result);

 

Join 稍微复杂一些

join其实比较适合写 "语句" 而不是一般的 "方法" 
语句看上去会好看很多

join 就是inner join 

要实现left join 可以只用一些巧妙方法

随便谈谈说join, 在1对多的情况,将会生产跟多的row,1的会被复制更多出来,有点笛卡尔积的feel 

如果是inner join ,匹配不到的row就被删除了, left join 是对 a table 进行完全保留,即使它某些row没有和 b table 匹配上.

看代码吧

            var result = from a in enum1
                         join b in enum2 on a.name equals b.name //equals 就是等于 =
                         where a["name"].ToString() == "xinyao" //这里可以加condition
                         orderby a["name"].ToString()
                         select new { name = a["name"].ToString(), like = b["name"] }; //to obj 
                      
            var result1 = enum1.Join(
                     enum2, //join table b
                     a => a.name, //on a 
                     b => b.name, //on b 
                     (a, b) => new { name = a["name"], like = b["name"] } //final result
                 ).Where(n => n.name == "xinyao").OrderBy(n => n.name); //后来才加

是不是差很多,下面的能看吗...

left join : 

into 关键字还可以有其它变化,这里只是其中一种使用它的方法。

            var result1 = from a in enum1
                          join b in enum2 on a["name"] equals b["name"]
                          into x  //这里的 x 就好比是 a 一样,a 是 enum1里的row不是table哦 
                          //select x; 请不要直接 select x, 因为这里的 x 已经因为innerjoin 而把不match的row删除了, 
                          select new { name = a["name"], row = x }; //我们新创建一个对象来收藏每个row, 这里如果x被删除的话,它应该是一个空值            
            foreach (var zz in result1) 
            {
                foreach (var yy in zz.row) 
                {
                    //没有匹配到 on 条件的话,zz.row是空的,也就不会进来这里了
                }
            }

 

好啦,还有很多留给下一篇吧

先记入在这里,下次才搬.

Javascript 里的 reduce 

reduce 有点循环对一个值做处理的概念,

定义一个初始值(它会一直跟着循环,然后我们可以对它做修改,loop完后返回这个值),可以叫他流动值

loop array时 每一次loop可以获取当前array的内容和获取这个流动值,每次loop的返回值是下一个loop的流动值,这就是它可以循环改造的原理了。

代码上 

这是javascript版 

        var array = [{ number: 1 }, { number: 2 }, { number: 3 }];
        var sum = array.reduce(function (total, obj, i, array) {
            return total += obj.number;
        }, 0);
        //原始值是0 , 流动值是total , obj 就是 loop array 当前的 对象啦。

这是c#版

    public class Obj
    {
        public Int64 number { get; set; }
    }

        List<Obj> array = new List<Obj> { new Obj { number = 1 }, new Obj { number = 2 }, new Obj { number = 2 } };
        Int64 sum = array.Aggregate(0, delegate(Int64 total, Obj obj)
        {
            return total += obj.number;
        });
  Int32 sum2 = array.Aggregate(0, (total, obj) => total += obj.number);
//简短版本,这样比较不容易指定类型,如果逻辑简单的话可以写这个,否则直接用委托吧。

   Aggregate 第一个参数,delegate第一参数,delegate返回值还有 sum 的类型一定一样,delegate 第2参数就是array内容的类型

 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:窗体与子线程的交互

下一篇:Log4Net 使用总结