Linq干掉for循环

在C系列语言中,for循环扮演着重要的角色。很难想象,一百行C代码里面没有一个for循环(我有个朋友,写了个几千行的算法,没有用的for循环,我当时很惊讶),就好比,一百行中文里面,没有一个"的"。可见,for循环是代码的基本构造块。由于for循环,一般是用来,对一串类型相同的对象进行操作的,从侧面可以看出,它经常伴随着"数组"而来的。用比较通俗的话说,"for循环"与"数组"是黄金搭档。

在C#里面,引进了foreach循环,它与for循环本质是相同的,由于在foreach循环中,省去了指标i(常常,只用来取第i个项,别无他用),很多人欣然接受了foreach循环,毕竟没有夺走for循环,它还在!
    编程语言一直在进化,先后经历了:...-汇编语言-...-过程式语言-...-面向对象语言-...。总体来说,越来越高级,越来越抽象。当代程序员可以不知道硬件是啥就可以编程;调用一个sort方法就排序了,不知道用的是"冒泡"还是"快速"排序算法(外国人都帮我们弄好了!每当认识到"差距超过20年"这个事实,我都...,好了,不想伤心事了!)。

在C# 3.0中,引进了Extension Methods,伴随而来的是一个新玩意儿Linq。用实用工具Reflector.exe打开System.Core.dll中的System.Linq命名空间,有个Enumerable静态类,其中有大量的对"数组"操作的扩展方法(你能想到的基本都有,不信就去看看!)。

对于用惯了for循环的朋友,如果要他/她停止使用,肯定会觉得日子没法过了。放心好了,我不会劝他/她停止使用的,就像戒烟一样,都是自己的事。(又一次跑题,言归正传!

下面我用代码来演示,如何用"扩展方法/Linq"来干掉"for循环":

[Test]
public void OldSum()
{
int sum0 = 0;
for (int i = 0; i < 10; i++)
{
sum0 += i;
}
Assert.AreEqual(45, sum0);
}

[Test]
public void NewSum()
{
int sum1 = Enumerable.Range(0, 10).Sum();
int sum2 = Enumerable.Range(0, 10).Aggregate((x, y) => x + y);
int sum3 = Enumerable.Range(0, 10).Aggregate(0, (x, y) => x + y);

Assert.AreEqual(45, sum1);
Assert.AreEqual(45, sum2);
Assert.AreEqual(45, sum3);
}

注:无论是对一串数字求和还是求积,归根到底,都是把一串东西变成一个东西,此时就用Aggregate

[Test]
public void OldFilter()
{
int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
List<int> odd_list = new List<int>();
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] % 2 == 1)
{
odd_list.Add(arr[i]);
}
}
int[] odd_arr = odd_list.ToArray();
Assert.That(odd_arr, Is.EquivalentTo(new int[] { 1, 3, 5, 7, 9 }));
}

[Test]
public void NewFilter()
{
int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] odd_arr = arr.Where(x => x % 2 == 1).ToArray();
Assert.That(odd_arr, Is.EquivalentTo(new int[] { 1, 3, 5, 7, 9 }));
}

注:无论是取奇数还是偶数,归根到底,都是取一串东西中的某些东西,此时就用Where

[Test]
public void OldMap()
{
int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
List<int> new_list = new List<int>();
for (int i = 0; i < arr.Length; i++)
{
new_list.Add(arr[i] * 10);
}
int[] new_arr = new_list.ToArray();
Assert.That(new_arr, Is.EquivalentTo(new int[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 }));
}

[Test]
public void NewMap()
{
int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] new_arr = arr.Select(x => x * 10).ToArray();
Assert.That(new_arr, Is.EquivalentTo(new int[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 }));
}

注:无论是x10还是+99,归根到底,都是把一串东西变成一串新东西,此时就用Select

[Test]
public void PrintMultiplicationFact()
{

Console.Write(
" 1 x 1= 1 \n"
+ " 1 x 2= 2 2 x 2= 4 \n"
+ " 1 x 3= 3 2 x 3= 6 3 x 3= 9 \n"
+ " 1 x 4= 4 2 x 4= 8 3 x 4=12 4 x 4=16 \n"
+ " 1 x 5= 5 2 x 5=10 3 x 5=15 4 x 5=20 5 x 5=25 \n"
+ " 1 x 6= 6 2 x 6=12 3 x 6=18 4 x 6=24 5 x 6=30 6 x 6=36 \n"
+ " 1 x 7= 7 2 x 7=14 3 x 7=21 4 x 7=28 5 x 7=35 6 x 7=42 7 x 7=49 \n"
+ " 1 x 8= 8 2 x 8=16 3 x 8=24 4 x 8=32 5 x 8=40 6 x 8=48 7 x 8=56 8 x 8=64 \n"
+ " 1 x 9= 9 2 x 9=18 3 x 9=27 4 x 9=36 5 x 9=45 6 x 9=54 7 x 9=63 8 x 9=72 9 x 9=81 \n"
);

/*********************方法一: 嵌套循环*************************/
for (int j = 1; j < 10; j++)
{
for (int i = 1; i < 10; i++)
{
if (i <= j)
{
Console.Write("{0, 2} x{1, 2}={2, 2}\t", i, j, i * j);
}
}
Console.Write("\n");
}

/*********************方法二: 扩展方法*************************/
Enumerable.Range(1, 9)
.SelectMany(j => Enumerable.Range(1, 9), (j, i) => new { i, j })
.Where(x => x.i <= x.j)
.GroupBy(x => x.j)
.Select(g => g.Aggregate("", (a, x) => a + string.Format("{0, 2} x{1, 2}={2, 2}\t", x.i, x.j, x.i * x.j)))
.ToList().ForEach(x => Console.WriteLine(x));

/*********************方法三: Linq表达式************************/
(
from j in Enumerable.Range(1, 9)
from i in Enumerable.Range(1, 9)
where i <= j
group new { i, j } by j into g
select new
{
LineNo = g.Key,
Line = g.Aggregate("", (a, x) => a + string.Format("{0, 2} x{1, 2}={2, 2}\t", x.i, x.j, x.i * x.j))
}

).ToList().ForEach(g => Console.WriteLine(g.Line));
}

注:对于嵌套的for循环,就用SelectMany

声明:for循环很好,你可以继续用,如果你想用的话。如果你喜欢尝试新东西,我想告诉你:"也许可以试试!"

附录1:乘法口诀

1 x 1= 1
1 x 2= 2 2 x 2= 4
1 x 3= 3 2 x 3= 6 3 x 3= 9
1 x 4= 4 2 x 4= 8 3 x 4=12 4 x 4=16
1 x 5= 5 2 x 5=10 3 x 5=15 4 x 5=20 5 x 5=25
1 x 6= 6 2 x 6=12 3 x 6=18 4 x 6=24 5 x 6=30 6 x 6=36
1 x 7= 7 2 x 7=14 3 x 7=21 4 x 7=28 5 x 7=35 6 x 7=42 7 x 7=49
1 x 8= 8 2 x 8=16 3 x 8=24 4 x 8=32 5 x 8=40 6 x 8=48 7 x 8=56 8 x 8=64
1 x 9= 9 2 x 9=18 3 x 9=27 4 x 9=36 5 x 9=45 6 x 9=54 7 x 9=63 8 x 9=72 9 x 9=81

附录2:完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace KSharp
{
    [TestFixture]
    public class TestForLoop
    {
        [Test]
        public void OldSum()
        {
            int sum0 = 0;
            for (int i = 0; i < 10; i++)
            {
                sum0 += i;
            }
            Assert.AreEqual(45, sum0);
        }

        [Test]
        public void NewSum()
        {
            int sum1 = Enumerable.Range(0, 10).Sum();
            int sum2 = Enumerable.Range(0, 10).Aggregate((x, y) => x + y);
            int sum3 = Enumerable.Range(0, 10).Aggregate(0, (x, y) => x + y);

            Assert.AreEqual(45, sum1);
            Assert.AreEqual(45, sum2);
            Assert.AreEqual(45, sum3);
        }

        [Test]
        public void OldFilter()
        {
            int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            List<int> odd_list = new List<int>();
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] % 2 == 1)
                {
                    odd_list.Add(arr[i]);
                }
            }
            int[] odd_arr = odd_list.ToArray();
            Assert.That(odd_arr, Is.EquivalentTo(new int[] { 1, 3, 5, 7, 9 }));
        }

        [Test]
        public void NewFilter()
        {
            int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            int[] odd_arr = arr.Where(x => x % 2 == 1).ToArray();
            Assert.That(odd_arr, Is.EquivalentTo(new int[] { 1, 3, 5, 7, 9 }));
        }

        [Test]
        public void OldMap()
        {
            int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            List<int> new_list = new List<int>();
            for (int i = 0; i < arr.Length; i++)
            {
                new_list.Add(arr[i] * 10);
            }
            int[] new_arr = new_list.ToArray();
            Assert.That(new_arr, Is.EquivalentTo(new int[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 }));
        }

        [Test]
        public void NewMap()
        {
            int[] arr = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            int[] new_arr = arr.Select(x => x * 10).ToArray();
            Assert.That(new_arr, Is.EquivalentTo(new int[] { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 }));
        }

        [Test]
        public void PrintMultiplicationFact()
        {

            Console.Write(
                   " 1 x 1= 1    \n"
                 + " 1 x 2= 2     2 x 2= 4    \n"
                 + " 1 x 3= 3     2 x 3= 6     3 x 3= 9    \n"
                 + " 1 x 4= 4     2 x 4= 8     3 x 4=12     4 x 4=16    \n"
                 + " 1 x 5= 5     2 x 5=10     3 x 5=15     4 x 5=20     5 x 5=25    \n"
                 + " 1 x 6= 6     2 x 6=12     3 x 6=18     4 x 6=24     5 x 6=30     6 x 6=36    \n"
                 + " 1 x 7= 7     2 x 7=14     3 x 7=21     4 x 7=28     5 x 7=35     6 x 7=42     7 x 7=49    \n"
                 + " 1 x 8= 8     2 x 8=16     3 x 8=24     4 x 8=32     5 x 8=40     6 x 8=48     7 x 8=56     8 x 8=64    \n"
                 + " 1 x 9= 9     2 x 9=18     3 x 9=27     4 x 9=36     5 x 9=45     6 x 9=54     7 x 9=63     8 x 9=72     9 x 9=81    \n"
            );

            /*********************方法一: 嵌套循环*************************/
            for (int j = 1; j < 10; j++)
            {
                for (int i = 1; i < 10; i++)
                {
                    if (i <= j)
                    {
                        Console.Write("{0, 2} x{1, 2}={2, 2}\t", i, j, i * j);
                    }
                }
                Console.Write("\n");
            }

            /*********************方法二: 扩展方法*************************/
            Enumerable.Range(1, 9)
                    .SelectMany(j => Enumerable.Range(1, 9), (j, i) => new { i, j })
                    .Where(x => x.i <= x.j)
                    .GroupBy(x => x.j)
                    .Select(g => g.Aggregate("", (a, x) => a + string.Format("{0, 2} x{1, 2}={2, 2}\t", x.i, x.j, x.i * x.j)))
                    .ToList().ForEach(x => Console.WriteLine(x));

            /*********************方法三: Linq表达式************************/
            (
                from j in Enumerable.Range(1, 9)
                from i in Enumerable.Range(1, 9)
                where i <= j
                group new { i, j } by j into g
                select new
                {
                    LineNo = g.Key,
                    Line = g.Aggregate("", (a, x) => a + string.Format("{0, 2} x{1, 2}={2, 2}\t", x.i, x.j, x.i * x.j))
                }

            ).ToList().ForEach(g => Console.WriteLine(g.Line));
        }
    }

  

时间: 2024-10-06 03:03:00

Linq干掉for循环的相关文章

(第一篇) 一步一步带你了解linq to Object

要想学好linq to object 我们必须要先学习lambda 表达式,学习lambda 表达式呢我们必须了解匿名函数和匿名类,学习匿名函数,我们必须学会委托,这是本文的宗旨.下面开始第一步.在第一步开始之前,我们做点准备工作,建立一个学生类和一个班级类,类结构如下 public class Student { public int Id { get; set; } public int ClassId { get; set; } public string Name { get; set;

python简单入门

一. 初识python. 1. 认识计算机 CPU(大脑) 3GHZ + 内存(DDR4) + 主板 + 电源(心脏)+ 显示器 + 键盘 +鼠标+ 显卡 + 硬盘 80MB/s 操作系统 windows 家用 linux 服务器 macOS 家用+服务器 计算机是一个高度集成的电子电路 高低电平. 二进制 二进制没有2 -> 0 1 八进制没有8 -> 0-7 十进制没有10 -> 0-9 十六进制没有16 -> 0-9 A-F 显卡 1. NAVID 看型号. 2. AMD 图

如何编写高质量的 JS 函数(4) --函数式编程[实战篇]

本文首发于 vivo互联网技术 微信公众号? 链接:https://mp.weixin.qq.com/s/ZoXYbjuezOWgNyJKmSQmTw 作者:杨昆 ?[编写高质量函数系列],往期精彩内容: <如何编写高质量的 JS 函数(1) -- 敲山震虎篇>介绍了函数的执行机制,此篇将会从函数的命名.注释和鲁棒性方面,阐述如何通过 JavaScript 编写高质量的函数. ?<如何编写高质量的 JS 函数(2)-- 命名/注释/鲁棒篇>从函数的命名.注释和鲁棒性方面,阐述如何通

在使用Linq to SQL并序列化一个数据对象的时候报System.InvalidOperationException异常,序列化类型XXX的对象时检测到循环引用。

在使用Linq to SQL并序列化一个数据对象的时候报System.InvalidOperationException异常,序列化类型 的对象时检测到循环引用. 异常信息(部分): System.Web.Services.Protocols.SoapException: 服务器无法处理请求. ---> System.InvalidOperationException: 生成 XML 文档时出错. ---> System.InvalidOperationException: 序列化类型 Web

使用gc、objgraph干掉python内存泄露与循环引用!

Python使用引用计数和垃圾回收来做内存管理,前面也写过一遍文章<Python内存优化>,介绍了在python中,如何profile内存使用情况,并做出相应的优化.本文介绍两个更致命的问题:内存泄露与循环引用.内存泄露是让所有程序员都闻风丧胆的问题,轻则导致程序运行速度减慢,重则导致程序崩溃:而循环引用是使用了引用计数的数据结构.编程语言都需要解决的问题.本文揭晓这两个问题在python语言中是如何存在的,然后试图利用gc模块和objgraph来解决这两个问题. 注意:本文的目标是Cpyth

[转]Linq使用心得——SelectMany替代二重foreach循环

本篇记录了Linq学习的心得,较为浅显,各位大牛请轻拍. 学习Linq其实已经很久了,但是一直没有使用的习惯,故水平也始终没有提高.近来刻意强迫自己用Linq来替代C# 2.0的一些写法.这里有一些心得和各位分享一下. 首先看下面两个类的定义: class Student { public int Score { get; set; } public Student(int score) { this.Score = score; } } class Teacher { public strin

.NET深入解析LINQ框架(一:LINQ优雅的前奏)

阅读目录: 1.LINQ简述 2.LINQ优雅前奏的音符 2.1.隐式类型 (由编辑器自动根据表达式推断出对象的最终类型) 2.2.对象初始化器 (简化了对象的创建及初始化的过程) 2.3.Lambda表达式 (对匿名方法的改进,加入了委托签名的类型推断并很好的与表达式树的结合) 2.4.扩展方法 (允许在不修改类型的内部代码的情况下为类型添加独立的行为) 2.5.匿名类型 (由对象初始化器推断得出的类型,该类型在编译后自动创建) 2.6.表达式目录树(用数据结构表示程序逻辑代码) 3.LINQ

linq和lambda基本操作

一.Linq有两种语法: 1. 方法语法 2. 查询语法 下面举个例子看看这两种方法的区别 比如现在有一个学生类 public class student { public string username { get; set; } public int age { get; set; } public string sex { get; set; } } 我们通过一个方法来添加很多同学 public IList<student> GetStu(int n) { IList<studen

C# LINQ 详解 From Where Select Group Into OrderBy Let Join

目录 1. 概述 2. from子句 3. where子句 4. select子句 5. group子句 6. into子句 7. 排序子句 8. let子句 9. join子句 10. 小结 1. 概述 LINQ的全称是Language Integrated Query,中文译成"语言集成查询".LINQ作为一种查询技术,首先要解决数据源的封装,大致使用了三大组件来实现这个封装,分别是LINQ to Object.LINQ to ADO.NET.LINQ to XML.它们和.NET