Hi 第一次来写东西,大家多多支持 (入题) 最近某天上班路上在微薄看到一哥们写的《在 JavaScript 中实现 LINQ 》看到里面关于 C#的 Linq 在实现 filter 和 map 的时候说道(reduce 已经在 python3 从全局空间去掉了,所以标题里面我加了个括号),如果同时调用类似 filter 和 map 这样的操作去遍历 List 的时候,实际上只遍历了一遍,像下面这样:
var array = new []{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var sum = array.Where(n => n % 2 === 0)
.Select(n => n + 3)
.Aggregate((sum, n) => sum + n, 0);
然后文章后面提到 JavaScript 中直接调用 filter 和 map 的时候,会重复遍历 Array ,比如像下面代码这样:
let array = [1, 2, 3, 4]
let sum = array.filter(n => n % 2 === 0)
.map(n => n + 3)
.reduce((sum, n) => sum + n, 0)
这样的话会先把 arrayfilter 成[2,4],然后再 map 成[5, 7],然后再 reduce 成 12 ,所以这个过程 array 会被重复遍历。
好了,下面说下 Python ,看完文章的时候然后我就好奇 Python 里面的 filter 和 map 是不是也是这样,会重复去遍历 List ,于是做了个实验: 像平时我们喜欢的函数式的写法:
In [1]: numbers = [1,2,3,4,5,6]
In [2]: list(map(lambda x: x + 1, filter(lambda x: x % 2 == 0, numbers)))
Out[2]: [3, 5, 7]
为了看清楚是不是重复遍历了 numbers 这个 List ,把 lambda 改写成个普通的 function 打印出来看看
In [3]: def is_even(number):
...: print('filter')
...: return True if number % 2 == 0 else False
In [4]: def inc(number):
...: print('map')
...: return number + 1
In [5]: list(map(inc, filter(is_even, numbers)))
filter
filter
filter
filter
filter
filter
map
map
map
Out[6]: [3, 5, 7]
上面可以看到, Python 这样直接调用 filter 和 map 也是会重复遍历 list 的。不过那哥们的文中提到后来能在 JavaScript 实现 Linq ,主要因为 ES6 支持 yield 和 Generator Function ,所以我想 Python 这两个都支持肯定也是可以实现类似 Linq 这样不重复遍历的 Magic 。
然后,再试了下之前很喜欢的一个函数式库 pyfunctional。这是个很值来安利一波的一个库,用了这个库后,摆脱了原生那种很丑的写法
# before
list(map(inc, filter(is_even, numbers)))
# afater
seq(numbers)\
.filter(is_even)\
.map(inc)\
.to_list()
嗯,很 Js 的写法....
好,回到正题,如果像上面这样调用 functional 时,发现整个过程只遍历的一次 List
In [7]: from functional import seq
In [8]: seq(numbers)\
...: .filter(is_even)\
...: .map(inc)\
...: .to_list()
filter
filter
map
filter
filter
map
filter
filter
map
Out[8]: [3, 5, 7]
果然是个好货,安利一波
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.