# LINQ之路 7：子查询、创建策略和数据转换

## 子查询

            string[] names = { "David Tim", "Tony Sin", "Rager Witers" };            IEnumerable<string> query = names.OrderBy(n => n.Split().Last());

        static void TestSubQuery()        {            string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };            // 获取所有长度最短的名字（注意：可能有多个）            IEnumerable<string> outQuery = names                .Where(n => n.Length == names　　　　　// 感谢A_明~坚持的指正，这里应该为==                    .OrderBy(n2 => n2.Length)                    .Select(n2 => n2.Length).First());      // Tom, Jay"             // 与上面方法语法等价的查询表达式            IEnumerable<string> outQuery2 =                from n in names                where n.Length ==　　　　　　　　　　　　// 感谢A_明~坚持的指正，这里应该为==                    (from n2 in names orderby n2.Length select n2.Length).First()                select n;             // 我们可以使用Min查询运算符来简化            IEnumerable<string> outQuery2 =                from n in names                where n.Length == names.Min(n2 => n2.Length)                select n;        }

            int shortest = names.Min(n => n.Length);            IEnumerable<string> query = from n in names                                        where n.Length == shortest                                        select n;

## LINQ查询创建策略

### 渐进式创建查询

• 使得查询易于编写
• 我们可以根据条件来决定是否调用某个查询运算符，如：if (includeFilter) query = query.Where(…)

            string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };            IEnumerable<string> query = names                .Select(n => n.Replace("a", "").Replace("e", "").Replace("i", "")                    .Replace("o", "").Replace("u", ""))                .Where(n => n.Length > 2)                .OrderBy(n => n);   // Result: Dck, Hrry, Mry

            IEnumerable<string> query =                from n in names                select n.Replace("a", "").Replace("e", "").Replace("i", "")                    .Replace("o", "").Replace("u", "");             query = from n in query                    where n.Length > 2                    orderby n                    select n;   // Result: Dck, Hrry, Mry

### into关键字

            IEnumerable<string> query =                    from n in names                    select n.Replace("a", "").Replace("e", "").Replace("i", "")                            .Replace("o", "").Replace("u", "")                    into noVowel                    where noVowel.Length > 2                    orderby noVowel                    select noVowel;   // Result: Dck, Hrry, Mry

            var query =                from n1 in names                select n1.ToUpper()                into n2                     //into之后只有n2可见                    where n1.Contains("x")  //Error: n1不可见                    select n2;

            var query = names                .Select(n1 => n1.ToUpper())                .Where(n2 => n1.Contains("x")); //Error: n1不再可见，lambda表达式中只有n2

### 包装查询

var tempQuery = tempQueryExpr

var finalQuery = from … in (tempQuery)

var query = from … in (tempQueryExpr)

            string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };             // 渐进式查询（Progressive query building）            IEnumerable<string> query =                from n in names                select Regex.Replace(n, "[aeiou]", "");             query = from n in query where n.Length > 2 orderby n select n;             // 用包装查询方式进行改写(Wrapping Queries)            IEnumerable<string> query2 =                from n1 in                    (                        from n2 in names                        select Regex.Replace(n2, "[aeiou]", "")                    )                where n1.Length > 2                orderby n1                select n1;             // 与上面等价的方法语法            IEnumerable<string> query3 = names                .Select(n => Regex.Replace(n, "[aeiou]", ""))                .Where(n => n.Length > 2)                .OrderBy(n => n);

## 数据转换

LINQ中的数据转换，也叫结果投影，是指LINQ查询select的输出。到目前为止，我们还只是看到了输出单个标量元素的示例。通过使用对象初始化器，我们可以输出更为复杂的结果类型。比如下面的示例，当我们在把姓名中的元音字母去掉之后，我还需要保存姓名的原始版本：

        class TempProjectionItem        {            public string Original;            public string Vowelless;        }         static void TestProjectionStrategy()        {            string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };             IEnumerable<TempProjectionItem> temp =                from n in names                select new TempProjectionItem                {                    Original = n,                    Vowelless = Regex.Replace(n, "[aeiou]", "")                };            //我们可以继续在结果中查询            IEnumerable<string> query =                from item in temp                where item.Vowelless.Length > 2 //按去除元音字母版本过滤                select item.Original;           //结果为姓名原始版本        }

### 匿名类型

            var intermediate = from n in names                               select new                               {                                   Original = n,                                   Vowelless = Regex.Replace(n, "[aeiou]", "")                               };            IEnumerable<string> query = from item in intermediate                                        where item.Vowelless.Length > 2                                        select item.Original;

### let关键字

let关键字让我们可以在保持范围变量的同时引入新的查询变量。比如上面的示例，我们可以用let关键字作如下改写：

            string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };            var query = from n in names                        let Vowelless = Regex.Replace(n, "[aeiou]", "")                        where Vowelless.Length > 2                        select n;   //正是因为使用了let，此时n仍然可见

let关键字非常灵活和方便，就像例子看到的那样。而且，我们可以使用多个let关键字，并且后面的 let表达式可以引用前一个let关键字引入的变量。

posted @ 2011-10-31 13:21  Life a Poem  阅读(17807)  评论(41编辑  收藏  举报