分享一行 Python 代码 `reduce(add, zip(nums[:n], nums[n:]))` - 来自解决 Leetcode #1470. Shuffle the Array 一题

2020-07-25 14:07:02 +08:00
 oahebky

本来是不会想要分享发出来的。

但是因为在 comment 区发了解法,然后有人问解释一下这行代码,所以就解释了一下。

本着解释都解释了,敲了那么多行字,所以不如分享出来给更多的人看到。


(the)Problem

[问题] :Leetcode#1470. Shuffle the Array

[描述] :

给你一个数组 nums,数组中有 2n 个元素,按 [x1,x2,...,xn,y1,y2,...,yn] 的格式排列。

请你将数组按 [x1,y1,x2,y2,...,xn,yn] 格式重新排列,返回重排后的数组。

示例 1:

输入:nums = [2,5,1,3,4,7], n = 3
输出:[2,3,5,4,1,7] 
解释:由于 x1=2, x2=5, x3=1, y1=3, y2=4, y3=7,所以答案为 [2,3,5,4,1,7]

示例 2:N/A

示例 3:

输入:nums = [1,1,2,2], n = 2
输出:[1,2,1,2]

[提示] :

来源:力扣( LeetCode ) 链接: https://leetcode-cn.com/problems/shuffle-the-array 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


Solution

我的一行解法:

class Solution:
    def shuffle(self, nums: List[int], n: int) -> List[int]:
        return reduce(add, zip(nums[:n], nums[n:]))

解释

对这一行代码的 explain:

https://leetcode.com/problems/shuffle-the-array/discuss/751957/Python-one-line-(Memory-Usage-less-then-100.00):-the-more-pythonic-way/629230


4151 次点击
所在节点    Python
53 条回复
mind3x
2020-07-26 02:19:07 +08:00
@linthieda 哦,那 Java, C++, Scala, Javascript, Swift, Rust 的 reduce 实现大概都很奇葩了 :)

Reduce 的并行版本对 combine 函数是有额外要求的:必须遵循结合律。你玩惯的只是刚好是并行的版本。
linthieda
2020-07-26 02:19:13 +08:00
@mind3x 但是我还是想说,我面的人如果这样用 reduce 我肯定给 N, 我不 care 一个具体语言里它怎么玩他的 API, 但你解题必须要体现出你的 cs 基本功, 非对易算符用了 reduce 结果是 inconsistent 的.
linthieda
2020-07-26 02:23:19 +08:00
@mind3x 大概是把实现造成的特性写在文档里让人 exploit 让我觉得奇葩.
mind3x
2020-07-26 03:00:57 +08:00
@linthieda 所以 Java, C++, Scala, Javascript, Swift, Rust 的 reduce 都是刚好实现成了一个特性?各家的 API 基本都是 reduce(combiner, iterator) 这一个类似的定义,既然数据流的定义是一个 iterator,自然行为就是从前到后,从左到右。这也能被扳成“把实现造成的特性写在文档里让人 exploit”,佩服。

为了避免继续抬杠下去,我就再补充一点:reduce 既然是从 iterator 拿输入,顺序自然是由 iterator 决定。给个 reverse iterator,顺序就反过来——但仍然是有序的!

再说一遍,并行实现的 reduce 才是更特例化的版本:combiner 要 associative,数据集也从简单的流式输入变成要完全放进内存的能随机访问的数组。
msg7086
2020-07-26 04:36:54 +08:00
@linthieda Reduce 本来就只是操作而非具体的实现。
就像 Hash 哈希表一样,有些实现里哈希表是按 Key 排序的,有些实现里哈希表是保持顺序的,有些实现里哈希表是乱序的。不能因为你用的 Hash 正好是乱序的,就把其他语言里有序的哈希表给批判一通吧?
同样 Reduce 本来指的也就是「归纳」操作,把多个输入处理成单个输出,至于是 Ordered reduce 还是 Unordered reduce,完全是看你语言的实现而已。没用过 CuDNN,但是很多语言里的 Reduce 都是 Ordered 处理的,所以你不 care 具体语言的这种想法本身就是错的。
Actrace
2020-07-26 09:38:01 +08:00
做程序员久了就是这样。以为自己写的代码别人看不懂就能突显优越感。这也是为什么这些算法网站能火的原因。
不过在老板眼里,业务能力差不能赚钱的话,立马就会被换掉~😂
在队友眼里,挖了一堆坑,谁都无法接手,恨不得爆锤~😂
capbone
2020-07-26 11:11:41 +08:00
reshape 一下不是更符合直觉么?

print(np.reshape(x, (2, -1)).T.flatten().tolist())
zzth370
2020-07-26 11:21:20 +08:00
看到各位大佬发言,学习到了,哈哈
lxilu
2020-07-27 00:29:58 +08:00
「一行」向来敏感,要是没有这个词肯定少很多争吵,我想楼主应该知道
oahebky
2020-07-27 09:23:08 +08:00
@lxilu
======
回复:

“一行”确实相对来说属于较敏感词。不过没想到有部分人反应会这么强烈,为了喷而喷,喷不到点上。

在我看来像函数式编程的语言和支持部分函数式编程的语言,能够合理使用一行的写法就该使用一行的写法。
人家弄一个函数出来,就是为了把定义变量、循环语句、等等重复的工作省掉。

我分享这行代码的出发点是因为几个高阶函数在解决这个问题的应用场景很典型 - 个人认为是个很好的学习 zip, reduce 的场景。
(如果更新成
`return reduce(lambda l, t: (l.append(t), l)[-1], zip(nums[:n], nums[n:])`
则没有 $O(tuple.\_\_add\_\_)$ => $O(n)$ 会造成
reduce(tuple.\_\_add\_\_, <tuple iter>) 的 $O(n^2)$ 性能问题)

======

“要不这样吧, 如果编程语言里有个地方你弄不明白, 而正好又有个人用了这个功能, 那就开枪把他打死。 这比学习新特性要容易些,然后过不了多久, 那些活下来的程序员就会开始用 0.9.6 版的 Python, 而且他们只需要使用这个版本中易于理解的那一小部分就好了(眨眼) 。”[^1] —— Tim Peters

[^1]: 给 comp.lang.python Usenet 小组的留言,2002 年 12 月 23 日, “Acrimony in c.l.p”( https://mail.python.org/pipermail/python-list/2002-December/147293.html ) 。
Shazoo
2020-07-27 09:26:41 +08:00
@gwy15
@mind3x

多谢二位解释~ tuple.add 的确是 O(N) 的操作。之前没多想过这个,直觉认为是 extend 类的操作…… immutable list 点醒梦中人。
necomancer
2020-07-27 09:49:59 +08:00
@capbone np.reshape(x, (2,-1)).ravel('F').tolist(),少个转置^^
shunia
2020-07-27 10:38:43 +08:00
虽然我不懂 python,但是我不影响我看 44 楼打脸打的好爽。最关键打脸就算了,还用英文打回去,痛快。
44 楼上面的兄弟让我想起三十而已里面的售货员,演着演着突然开始飙英文,这也就算了还自己骗自己(明知不婚是坑)。
PS: 我对剧和演员和演员所代表的人群都没有任何偏见,纯粹联想到而已

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/693010

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX