奇怪的|奇怪的 Powershell
本文用来收集一些使用 Powershell 的时候的一些奇奇怪怪的体验。
0x00 :: 生存还是毁灭?
在操作 集合
(比如 数组
、 链表
、 哈希映射表
等)的时候,有一种叫 算子
的概念。
在 Scala 里它本质上是一些对象的方法,一些语言里它被叫做「高级函数」。
【奇怪的|奇怪的 Powershell】这里主要需要先知道这俩:
map
: 对集合
里的每一个元素
,都指定一个计算的逻辑,该算子
可以返回一个新的集合
,里面每个元素
都是上一个集合每个元素
经过该逻辑后的值。
- 比如:
{2,3,3}
这个集合,经过map(你们每个都乘以3)
处理后,就能返回{6,9,9}
这样的集合。
- 比如:
flatten
: 把一个集合
里,若有的元素
也是集合
,那么该算子
会返回一个打破一层里面集合的新集合。
- 比如:
{{1,2},7,{2,3,3},{2,{6,6,6},12},4}
这个集合,经过flatten
处理后,返回的集合就是{1,2,7,2,3,3,2,{6,6,6},12,4}
这样的。
- 比如:
flatmap
: 其实,flatmap(xxx)
就等同于先map(xxx)
然后flatten
。
- 比如:
假如,集合乘法效果是这样:{1,2,3} * 2 => {1,2,3,1,2,3}
,
那么,{{1,2},7,{{2,3,3}}}
经过flatmap(每个元素给我乘2)
后,就等于先被变成{{1,2,1,2},14,{{2,3,3},{2,3,3}}}
这样,再变成{1,2,1,2,14,{2,3,3},{2,3,3}}
这样。
这其实就好像,你有一个小破船,船上运者一些货物,有的货是普通货、有的货也是小破船,就叫小小破船好了。现在,小破船被鱼雷击中了,这除了导致里面的货物同样被颠簸了一下以外,那些小小破船都被颠簸侧漏了。小小破船上的货物就都漏了出来,从而它们不再在小小破船上了、而是漏到了小破船上,乱七八糟地、平铺地,摊在那里。
- 比如:
foreach
: 在 Scala 里的话这个其实就是无返回(即返回Unit
表示返回空)的map
。一般是要用每个元素做同样一件有副作用的事。(比如打印)(这里只要信息不只通过返回传出or
信息不只通过参数进入函数就都算有副作用)
上面的而本部分要说的,就是 Powershell 的flatmap
是前两者的组合而foreach
可理解为特殊的 map
那么上面的确只是说了俩算子
,没错。
foreach
似乎有着类似于 flatmap
的作用这件事了。就是说,「里面的东西」,存在还是毁灭?要不要击破小小破船、以使其侧漏?示例
先简单测试,再演示一个稍微复杂的例子进一步验证。
0.0
1,2,(1,2,3) | foreach { $_ * 3 }
应有输出:
3
6
1
2
3
1
2
3
1
2
3
可以看到其中的
(1,2,3)
被重复了三次而没有数值三倍0.1
1,2,(1,2,3) | foreach { $_ * 3 } | foreach { $_ * 7 }
应有输出:
21
42
7
14
21
7
14
21
7
14
21
可以看到上一步的结果的
集合
里其实就已经是平坦的了,那个 (1,2,3)
在乘以三的时候还是一个 集合
,但乘以三完了以后也一并被侧漏了开来,在乘以七的时候,就是漏出来的每个元素像前面两个元素一样都被作为外层 集合
的直属元素来对待了。1.0
1,2,,(1,2,3) | foreach { $_ * 3 } | foreach { $_ * 7 }
这里给开头代码断下句:两个逗号
,,
并不是一个整体,像 1,2
的逗号作用就像 1+2
的 +
一样是一个运算符,二元的,相当于一个两参数的函数,只不过,算式 1,2
的返回结果是个元素为 1
和 2
的数组;而 ,2
其实也可以类比着 +2
来理解,也是运算符,一元运算符,只不过 ,2
的返回还是个数组,一个单元素的数组。所以,不难理解,这里的
,(1,2,3)
才是一个整体,手动明确一下运算符的优先级的话,开头那块儿的 1,2,,(1,2,3)
就应该是这样写了: 1,2,(,(1,2,3))
。它应有这样的输出:
21
42
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
可以看见这回里面的
(1,2,3)
没有轻易侧漏。但真的是这样吗?1,2,,(1,2,3) | foreach { $_ * 3 } | foreach { $_ * 7 } | foreach { $_ * 2 }
看看输出:
42
84
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
2
4
6
1.1
可以看到,其实经过两层 flatten
后,里面的 数字元素们
都已经平铺到了外面,再到第三层的逻辑为 让所有元素乘以二
的转化操作的结果,就是都被作为数字来操作了。就如同是,小破船上的小小破船,在颠簸后终于上完了厕所,然后永远地离开了这个它们原本所在的小破船。
总结
可见,在 Powershell 里,
foreach
其实和 flatmap
有类似的逻辑,或者说二者就是一样的。其实它确切的名字是
ForEach-Object
,而 foreach
则是别名,而且它还有个更短的别名: %
。 (这部分的知识来源:
https://www.jb51.net/article/115518.htm
)而它为何会成为
flatmap
,或许就可以讲另一个故事了吧。我个人的猜测是这是 Powershell 上的一个特性(都这么久了应该不是BUG了吧),即在被返回时会自动拆一次。你可以试试 1,2,(1,2,3)
和 1,2,,(1,2,3)
对比一下并看看后者的提示。之所以同
flatmap
联系起来是因为看了这些:https://stackoverflow.com/questions/10442333/what-is-the-powershell-equivalent-to-linqs-select
https://stackoverflow.com/questions/5241441/powershell-equivalent-of-linq-selectmany-method
https://insbex.jixun.moe/linq-in-pwsh
https://or1ko.hatenablog.com/entry/20100125/1264425759
不过并没提及 FlatMap 。不过,如果元素确保不会有
集合
,那么 %
的表现的确等同于 map
算子了。而之所以能把
flatmap
和 foreach
联系起来,还是因为前两个链接里有的回答举的例子,特别是第一个链接里,直接问了这方面的事情。xxx
推荐阅读
- 奇安来了
- 读《奇人异士见闻录》有感
- 突然间感觉到写作的乏力
- 07/22【晨读感悟】保持好奇心,生活才有无限可能
- 欢乐小分队内蒙东北行第六站(第十二天)五大连池印象之(奇特壮观的火山地貌景观)
- 心情的样子
- 2018-11-27今天属于宇宙,这是我送给他的礼物|2018-11-27今天属于宇宙,这是我送给他的礼物|我的奇迹日记Day27
- 惊奇于世界,还热爱于生活
- 第七课|第七课 《庄子》的奇幻世界
- 车子掉沟里了,奇葩车主却很开心