【C#杂谈】当Grasshopper中的C# Scriptable电池遇到LinQ,抛弃Python的理由又多了一条
LinQ的全称Language Integrated Query,是一种将数据库理念,比如常用的查找(Select)、排序(Order By)、条件过滤(Where)等延伸到一般编程中的技术路径。
Grasshopper的日常使用其中也包含了大量数据传递/使用的过程,比如按一定规律生成一系列点、将一系列直线按某种条件过滤掉等。虽然Grasshopper自带的运算器可以实现这些功能,但是有时候需要拖入大量的电池来实现一个简单的过滤逻辑。比如要从一堆点里选出X坐标大于1且小于5的点,如果只使用Grasshopper自带的电池,就需要用到下列的电池组
这时候Python就能派上大用场了:使用Python电池,一行就搞定了
a = [pt for pt in x if pt.X > 1 and pt.X < 5]
虽然,C# Scriptable电池也能做得到这一点…… 但是这代码量可能就得多一点了
var list = new List<Point3d>();foreach (var item in x)if (item.X > 1 && item.X < 5)list.Add(item);A = list;
所以,很多时候,对于这类纯粹的数据操作(不涉及到几何运算、复杂对象操作)而言,Python往往获得了更多的人的青睐 —— 既能少写代码,又能让代码看起来更酷,列表生成式的逻辑表达也十分清楚。
反观C#的代码,foreach
循环套一个if
条件判断,代码量比Python多,看起来也平平无奇,没有亮点嘛。
但是,C#真的如此吗?
加上System.Linq
命名空间,C#也能变得很酷:
using System.Linq;
// ... ...A = x.Where(pt => pt.X > 1 && pt.X < 5);
下面是过滤处理100,000个数据点时,各个代码的效率对比,作为对照组,下面两个电池不做过滤,直接原路输出数据,作为对照。
Python的对照组居然比过滤后需要的时间更多?这是因为Python电池在运行时需要把来自Grasshopper内置的对象转换成为Python对象之后,才能在Python电池里处理,然后在输出时又要转回Grasshopper的对象,这需要对象被转换两次。因为过滤后的点的数量会变少,所以转换对象数量变少了,电池的运行时间就会变短。
Grasshopper本身就是C#写的,所以C# Scriptable电池在使用过程中不存在类似于Python一样的对象转换的过程,因此直接将点的列表原封不动地传出所需要的时间更少。
using System.Linq;
哪里能用Linq?
System.Linq
命名空间里包含了对IEnumerable
接口的一系列的扩展方法,只要对象遵循IEnumerable
接口(你能想到的所有的存储多个对象的存储结构都会遵循这个接口,比如List
、Array
、Dictionary
、Stack
、Queue
、……),都能直接使用Linq。
换句话说,无论哪都能用Linq,只要你想。
匿名函数
匿名函数又叫Lambda函数,语法为
(参数类型 参数名称, ...) => { 函数体 };
参数由逗号分隔,函数的返回值类型由函数体内的返回值确定,如果没有返回值则返回类型是void
。
lambda函数是Linq使用的精髓,它能让Linq语法更简练、更有逻辑。比如前面中用来过滤的.Where()
函数中就是用了过滤条件的lambda函数
pt => pt.X > 1 && pt.X < 5
写全其完整版本就是
(Point3d pt) => {return (pt.X > 1 && pt.X < 5);}
也就是这个函数是“输入参数是Point3d
类型,返回值是bool
类型”的一个匿名函数。
因为只有一个参数,且参数类型由.Where()
前的IEnumerable
中包含的对象类型确定了(此处,x
的类型是List<Point3d>
,因此可以确定函数的参数类型为Point3d
),所以可以省略( )
。因为函数体只有一行表达式,所以可以省略{ }
。
在x.Where()
执行时,会将来自列表x
的所有的每一个对象作为输入参数,执行一遍这个匿名函数,如果返回值是true
,则保留该对象,返回值是false
则滤掉该对象,最终只会留下
“将对象作为输入放入Lambda函数中,返回值是true
”
的这一批对象。
x.Where( pt => pt.X > 1 && pt.X < 5 )
差不多等价于
bool Lambda_Func(Point3d pt)
{return (pt.X > 1 && pt.X < 5)
}foreach (var item in x)
{if (Lambda_Func(item))// 接收这个对象else // 滤掉这个对象
}
当然,也可以不用匿名函数,因为.Where()
接收的是一个函数参数,也可以这样:
bool FilterFunction(Point3d pt)
{return (pt.X > 1 && pt.X < 5)
}var filteredPoints = x.Where( FilterFunction );
把我们的过滤条件变成一个有名字(FilterFunction)的函数,既然有名字就不能叫“匿名”函数了,不过作用还是一样的。
由于大概率这类函数仅仅会用到这一次(过滤完数据之后就不会用到了),所以很多时候我们并不会费劲地给这个函数起个名字,直接使用匿名函数构造一个只用一次的函数就可以了。而且还能让逻辑变得更清晰。
Select
使用Select()
可以将IEnumerable
中的对象作为参数,转换整个IEnumerable
的对象类型。简单点来说,这是一个单行foreach
。
看下列的代码,直接复制到 https://dotnetfiddle.net/ 去执行(这是一个在线编译器,可以方便测试小代码)
using System;
using System.Collections.Generic;
using System.Linq;public class Program
{public static void Main(){var i = new List<int>{ 1, 2, 3, 4, 5, 6 };var j = i.Select(num => Math.Sqrt(num));foreach (var jtem in j) Console.WriteLine(jtem.ToString());}
}
可以看到,通过一个Select
命令将i
中的整数通过匿名函数num => Math.Sqrt(num)
“投影”到了j
中去,相当于i
中每一个对象都被扔到匿名函数中执行了一遍,将结果放到了j
中去。有些时候这种操作叫做管道。这是很典型的函数式编程的思想。
为什么这种操作叫做SELECT呢,这是因为实践当中它一般是不会涉及计算的,一半它是用来批量获取一个类中的某个特定属性,比如所有点的X坐标:
List<Point3d> pointList = new List<Point3d>();
// ... ... ...
// ... ... ... 填满这个点的列表
// .... . ...
var pointX = pointList.Select( p => p.X );
这样就十分的简单、高效。
Where
最开始的例子就提到了使用Where
的最常用的情况了。只需给出一个“返回值是bool
”的匿名函数,就能把原数据中“匿名函数返回为true
”的对象选出来。
在 https://dotnetfiddle.net/ 中试试看这段代码:【选择所有的偶数】
using System;
using System.Collections.Generic;
using System.Linq;public class Program
{public static void Main(){var i = new List<int>{ 1, 2, 3, 4, 5, 6 };var j = i.Where( n => n%2 == 0 );foreach (var jtem in j) Console.WriteLine(jtem.ToString());}
}
OrderBy
以某种方式排序,它用到的匿名函数所需要的返回值是一个“可比较”的类型,比如int
、double
等。一个直观的例子,比如我们想要对一堆点排序,但是点由X、Y、Z三个坐标值构成,我们要以什么排序呢?那这里匿名函数就要返回这个 “排序的依据” 。
比如我们这以Y坐标为依据来排列点的顺序:
电池中的代码仅有一行:
A = x.OrderBy(pt => pt.Y); // 匿名函数返回值为 Y 坐标,用于作为排序依据
返回啥就会按照啥来排序。
OrderByDescending
跟OrderBy
一样,但是是从大到小排。
倒序排列。
ToList 和 ToArray
前面提到的所有的Linq语法的结果都是一个IEnumerable
对象,不支持通过序号去访问其中的对象,比如x[10]
。但是我们很多时候需要这样的功能,所以怎么把Linq的语法结果换成我们常用的List
或者Array
呢,就是使用ToList()
和ToArray()
。
它们不需要输入任何参数。
var i = new List<int>{ 1, 2, 3, 4, 5, 6 };
var j = i.Where( n => n%2 == 0 ); // j 是一个 IEnumerable<int> 类型List<double> doubleList = j.ToList(); // 转换成为 List<int>
// ... ...
将它们连起来
Linq语法最有优势的一点就是它能连起来使用,让整个数据流逻辑变得清晰无比:
比如在Grasshopper从一堆点里:
- 挑出来X在1到5之间
- Y在2到8之间
- 并以这些点为圆心画一个圆,其半径为它自己的X坐标与Y坐标的差值
- 将这些圆以圆心的Y坐标排序 (小到大)
- 将这些圆放到
List
中去
当我想到要拖多少个电池的时候,我已经不想说话了,那将会是一个灾难。
但是用Linq:
List<Circle> circleList = x.Where(pt => pt.X > 1 && pt.X < 5).Where(pt => pt.Y > 2 && pt.Y < 8).Select(pt => new Circle(pt, Math.Abs(pt.X - pt.Y))).OrderBy(c => c.Center.Y).ToList();
妙啊!
自从用熟了Linq,在Grasshopper中Python电池已经吃灰好些日子了……
【C#杂谈】当Grasshopper中的C# Scriptable电池遇到LinQ,抛弃Python的理由又多了一条相关推荐
- 在Grasshopper中使用C#开发之(一)——C#调用Grasshopper中的电池
目录 前言: 1.查看所有可以调用的电池的名称 2.设置引用 3.主体代码 (1)方法1:返回列表,便于后续处理,推荐使用 (2)方法2:返回的results是object[ ] 类型,在处理有些问题 ...
- python开发grasshopper插件_在Rhino/Grasshopper中使用Python
一些基本的信息可以在官方网站(http://wiki.mcneel.com/developer/python)找到. 让人遗憾的是,目前还没有方便有效的方法可以在Rhino/Grasshopper中使 ...
- Postgresql杂谈 09—Postgresql中的Gist索引的深入学习
本文,我们进一步学习下Gist索引.Gist是Generalized Search Tree的意思,意思是通用搜索树,底层结构也是一种平衡树,它是一套索引模板,可以支持用户实现自定义的索引.相比于BT ...
- python游戏中调整箭头下落速度_入门 | 三行Python代码,让数据预处理速度提高2到6倍...
原标题:入门 | 三行Python代码,让数据预处理速度提高2到6倍 选自TowardsDataScience 作者:George Seif,机器之心编译 在 Python 中,我们可以找到原生的并行 ...
- Python使用datetime中的timedelta模块实现时间增减:python计算100天后是哪年那月那日?
Python使用datetime中的timedelta模块实现时间增减:python计算100天后是哪年那月那日? 目录
- python函数def里面嵌套def,python菜鸟求问关于嵌套函数中作用域范围应该怎么理解?,python嵌套,直接上代码def l(l...
python菜鸟求问关于嵌套函数中作用域范围应该怎么理解?,python嵌套,直接上代码def l(l 直接上代码def l(list): def d(): return list return d ...
- 在python中、下列代码的输出是什么-python期末考试试题汇总
6.for i in range(2,n): if n%i==0:break if i==n-1: print('是素数') else: print('不是素数') 7.'abcabcabc'.cou ...
- python random模块中的指令_10分钟让你掌握python编程中random模块功能使用,非常详细...
原标题:10分钟让你掌握python编程中random模块功能使用,非常详细 python作为一门高级编程语言,它的定位是优雅.明确和简单.阅读Python编写的代码感觉像在阅读英语一样,这让使用者可 ...
- DL中版本配置问题:TensorFlow、Keras、Python版本完美搭配推荐
DL中版本配置问题:TensorFlow.Keras.Python版本完美搭配推荐 目录 TensorFlow.Keras.Python版本完美搭配推荐 TensorFlow.Keras.Python ...
- ML之XGBoost:XGBoost参数调优的优秀外文翻译—《XGBoost中的参数调优完整指南(带python中的代码)》(四)
ML之XGBoost:XGBoost参数调优的优秀外文翻译-<XGBoost中的参数调优完整指南(带python中的代码)>(四) 目录 Step 3: Tune gamma步骤3:伽马微 ...
最新文章
- Python使用sklearn构建广义线性模型:Tweedie回归(Tweedie regression)实战
- 四大传值详解:属性传值,单例传值,代理传值,block传值
- 80后应该面对的问题
- 6.7级地震!北海道数据中心陷最长停电危机!
- c++实现读写共享锁
- Java命令:jinfo — 查看进程参数
- 移动web开发之rem布局(rem基础、媒体查询、 less 基础、rem适配方案)
- nodejs nodemailer
- 第八章:软件包的安装与管理
- Python学习 第3天 VS与PyCharm使用对比
- mysql乐观锁与事务_Mysql中的读锁,写锁,乐观锁及事务隔离级别和并发问题
- 杭电 1021 找规律
- 【软工】第一次阅读作业
- python利器能下载库吗_python利器
- UTF-8是如何编码的?
- 华为状态栏图标替换_【新手教程】状态栏图标替换教程
- 003_Kubernetes核心技术
- 2018.06.25 一个不知道叫什么好的U盘启动工具集
- mongodb java 内嵌文档_MongoDB 内嵌文档
- 常见元素 – p元素