Pulpcode

捕获,搅碎,拼接,吞咽

0%

使用c#的linq和python的函数式编程操作集合

Start

作为一个一开始编写c的程序员,刚接触c#(静态)或者是python(动态)这样”现代化的语言时”,编写代码的时候常常是使用古老的解决方案。这就是没能理解一门语言的表现。所以这篇博客想总结一下,对集合的操作,有哪些古老的做法,而在”现代语言“中又是如何解决的。

说语言不重要,重要的是编程思维,这种说法确实很是扯淡,因为你用什么语言就决定了你的编程思维,如果你没有长时间使用一门语言,去吸取它的精华,那么你根本不会有什么编程思维,也只能用各种语言写C代码

说到数据库我们经常会说“增删改查”。对于集合而言也基本是这些操作。

比如将一个整型数组中大于5的元素过滤出来,我们一直会写这样的代码:

1
2
3
4
var bar = new List();
foreach i in foo:
if i > 5:
bar.add(i)

也许python中也可以编写类似的代码,不过使用列表生成器可能会让代码简单一点。

1
bar = [ i for i in foo if i > 5 ]

但是还是类似的思维方式。

如果你能对集合换个思维方式,使用linq或函数式编程来操作它们,那么就会简单的多了。

1
var bar = foo.where(r => r > 5);
1
bar = filter(lambda x: x>5, foo)

还有就是对一个集合内的所有元素进行判断,比如这里判断一个集合是否所有元素都是偶数,如果是早期的写法,那么会是这样的:

1
2
3
4
5
6
7
8
// 以下代码在一个函数内部:
foreach (var item in collection)
{
if(item%2 != 0){
return false;
}
}
return true;

如果用linq会好很多:

1
collection.All(r => r%2 == 0);

任意的逆命题是存在,而判断一个集合中是否存在符合某个条件的元素同样简单。

1
collection.Any(r => r%2 ==0);

不知道python中是否有工具包来对集合进行All或者Any操作,即使没有,自己“包装”一个也是很简单的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def any(function, iterable):
'''
存在
'''
for element in iterable:
if function(element) == True:
return True
return False

def all(function, iterable):
'''
任意
'''
for element in iterable:
if function(element) == False:
return False
return True

再比如对一个集合进行求和,这也许是当年练习c和c++代码时,都写爆的东西。

1
2
3
4
5
int sum = 0;
foreach(var item in collection){
sum += item;
}
return sum;

那么用linq来写这段代码将会简单许多。

1
collection.sum(r => r);

其实用python的reduce来写这段代码同样有趣。

1
reduce(lambda x,y: x+y, foo)

还有就是一个在orm中常用的语句,因为即使你查询的结果只有一个元素,返回的也是一个集合。这
样first操作很好用了,你不用单独index取它,写出来的代码会非常整齐。

1
Student.Select(r => r.Name).Where(r => r.Sex = 0).First();

上面那些所谓古老的代码还是因为使用了迭代器,否则如果是在c语言的for中去写这些代码,将会更加难受。

你会发现,这种对集合的操作都是力求不去修改原来的集合并返回一个新的集合。

从我现在的编程经验来看,能修改原集合确实是一个不好的操作。

这种思维进化的关键是能够把集合本身抽象成一个整体,而不是一个一个的去迭代它的元素。