V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
levelworm
V2EX  ›  程序员

不知道为什么,我很厌恶 map()

  •  1
     
  •   levelworm · 6 天前 via Android · 5313 次点击

    首先声明一下,我承认我是个很烂的程序员。我甚至不愿意承认自己是程序员。(也许这就是原因?)

    因为公司转向 Flink ,所以今天决定学习一下。但是不知道为什么,看到 map()就觉得生理上的厌恶,和看见一只蟑螂一样。

    其实我自己也不能理解这种厌恶--我能理解为什么自己不喜欢,因为 map()本身没有可读性,你看到这个,就得去里头看到底是调用了什么函数。但是我不知道为什么我会有生理上的厌恶。同理,我在 PySpark 里看到 map(),也会极其厌恶,尤其是配合 lambda 食用,则更加厌恶。比如说

    result = map(lambda x: x["id"], data["item"])
    

    看到一次我就恶心一次。

    不知道有没有类似的朋友,你们是如何克服的?我看了一下,Flink 里似乎无法避免 map()。所以只能自己习惯了。

    44 条回复    2025-02-03 11:15:38 +08:00
    iintothewind
        1
    iintothewind  
       6 天前   ❤️ 2
    那是因为你用的 Python, 强类型动态语言, 而且传入参数没有 type hint 的原因吧.
    你试试用用 Scala 不就好多了.
    sagaxu
        2
    sagaxu  
       6 天前   ❤️ 7
    跟你相反,我非常喜欢 map/filter/reduce/fold/chunk...,意图+操作,可读性强,且非常直观
    levelworm
        3
    levelworm  
    OP
       6 天前 via Android
    @sagaxu #2
    问题在于,map()意图清晰在哪里?只是知道要做个变换,具体是什么还得看里头啊。还是说我理解错了?

    好吧,也许改成 transform()我就能接受了。真是奇怪的心理。
    levelworm
        4
    levelworm  
    OP
       6 天前 via Android
    @iintothewind #1
    有可能,但是我觉得 Python 那段,用 list comprehension 就好很多。
    aresyang
        5
    aresyang  
       6 天前   ❤️ 1
    或许了解 fold_left mnist 后就还好
    netabare
        6
    netabare  
       6 天前   ❤️ 1
    不过是个 Functor 而已。

    或者也许 Python 的 lambda 语法太丑了。要是换成 map (fn x => x + 1) [1,2,3,4] 这不就清晰多了吗。

    List comprehension 这玩意能出现的前提是它是个 monad ,按照那个著名的话,monad 得先是个 functor ,换句话说能写出 list comprehension 的东西,它也肯定会写得出 map……这不就变成先有鸡还是先有蛋的问题了。
    sagaxu
        7
    sagaxu  
       6 天前   ❤️ 1
    @levelworm map 的清晰点在于,我不必定义一个 array/list 数据结构,然后把元素转换后 append 上去,而是直接告诉数据源,对这个集合的每个元素做一个映射,得到一个新集合,剥离了数据结构实现细节。你觉得别扭,可能是因为 python 的 lambda 语法不太友好。
    w568w
        8
    w568w  
       6 天前   ❤️ 1
    是这个 map 的命名和设计都比较反直觉。看到 map 这个单词,我大脑里的反应顺序是:

    1. 创建 hashmap ?
    2. 创建映射?
    3. 哦都不对,是 ([a], f) -> [f(a)]

    然后我自然的思考顺序是「对什么做映射?」,然后扫过第一个参数,发现是个很懵逼的 lambda 或者一个变量(然后往上翻了半天才发现这个变量是一个 function ),再仔细一想才发现不对,map 的第一个参数是映射……

    参数顺序这一点非常反人体工学,因为中文这个语言先说上下文,比如会说「对某物做什么事」,而不常说「做什么事对某物」:我得先知道你在操作什么列表,然后你 lambda 函数里的各种引用、操作对我才有意义。把映射函数放在前面,对我来说是一个非常破坏阅读心智连贯性的设计。
    levelworm
        9
    levelworm  
    OP
       6 天前 via Android
    @netabare 这倒是,不过我的确智商不足理解函数式编程,除非比较符合我的直觉。。。也可能用用就好了,反正逃不掉。
    levelworm
        10
    levelworm  
    OP
       6 天前 via Android
    @sagaxu #7
    这个我能理解,我其实就是不喜欢他叫 map 。。。R 的 apply 都好多了。我怎么这么矫情。
    abc612008
        11
    abc612008  
       6 天前   ❤️ 2
    建议写写 ML 语言脱敏。或者写下 scala/kotlin 这种 map 比较好看的语言 e.g. `listOf(1,2,3).map{it * 2} == listOf(2,4,6)`
    levelworm
        12
    levelworm  
    OP
       5 天前 via Android
    @abc612008 #11
    好吧我承认我的智商不足以写 ML 系。。。
    mizuhashi
        13
    mizuhashi  
       5 天前   ❤️ 1
    @w568w 函數式語言裏面 map 的返回值可以是一個函數,而且是可以組合的,所以例如 Haskell 可以這麼寫:`(map (+1) . map (*2)) [1, 2, 3]` 輸出 [3, 5, 7]。`map (*2)`返回一個可以把每個元素*2 的函數,然後`.`可以把兩個 map 的返回值連起來。不過 python 的 map 不知道有沒有這種性質,如果沒有的話確實沒必要把函數放前面。
    user8341
        14
    user8341  
       5 天前   ❤️ 2
    Flink 和 Spark 之所以使用 map 是因为它们受到了谷歌最早的 MapReduce 模型的启发。

    使用这一套技术编写程序,可以轻松地利用集群的计算能力。map 操作将任务分解,并分发给多台机器同时处理。而 reduce 操作则将计算结果汇总到一个节点,从而得出最终结果。
    nkcfc
        15
    nkcfc  
       5 天前 via Android   ❤️ 1
    map 大概就是数学上的映射或者函数,当然得有个 f 和集合了,f 在前面不是很自然吗? apply 和 map 一般不同,用于支持任意多变量的函数。
    nkcfc
        16
    nkcfc  
       5 天前 via Android   ❤️ 1
    建议多学学数学,我现在受不了用 C 风格的代码计算这个例子,定义一个空数组,然后不断添加元素?
    levelworm
        17
    levelworm  
    OP
       5 天前
    @nkcfc #16
    没办法啊,各有所爱,能理解。
    hefish
        18
    hefish  
       5 天前   ❤️ 1
    支持 op 的讨厌。也支持我自己的不讨厌。
    kagenomirai
        19
    kagenomirai  
       5 天前   ❤️ 2
    OP 只是不适应而已,就像第一次学极限的定义的时候,怎么看怎么恶心。
    但后续理解了习惯了,不也一样用得飞起。
    另外 python 的语法可读性我觉得太差了(太多 keyword 真影响阅读)。
    当然最好的适应方式就是去学一个 ML 系的语言,学的过程中抛弃过程式的思考方式。
    然后你就可以做到过程式和函数式两种思考方式之间任意切换了。
    虽然只是为了一个 map 就花时间在 ML 上感觉有点浪费,不过程序员就是需要不断接受新东西(所以我本身也不喜欢程序员)。

    关于 map 的命名。
    其实首先登场的是 fmap ,意思是对一个 functor 进行映射。
    functor 可以简单理解为一个复合数据,可以改变其中的元素同时不改变结构。
    去掉 f 得到 map 的意思就是对一个特定数据映射(一般都是 list 或者 array )。
    sir283
        20
    sir283  
       5 天前 via Android   ❤️ 1
    这些动态语言的 map 跟 lambda 都不怎么好阅读,我觉得只有 C++跟 Java 的才好阅读。
    iseki
        21
    iseki  
       5 天前 via Android   ❤️ 1
    语法设计导致的吧,我也非常讨厌 Python 的 lambda ,非常丑陋。但是 Kotlin 的很美
    aijam
        22
    aijam  
       5 天前   ❤️ 1
    一直印象中 Python community 就是推荐 comprehension over map 。
    map 唯一实用的场景是 zip 多个 list 的时候可以 map(fn, list1, list2, ...)。
    非必要不 map
    NickLuan
        23
    NickLuan  
       5 天前   ❤️ 1
    不习惯可能是因为 map/filter 这些函数独立出来了,如果像 js 那样挂在 array 下面会可读好一些?
    guanhui07
        24
    guanhui07  
       5 天前   ❤️ 1
    我也非常喜欢 map/filter/reduce/chunk...,意图+操作,可读性强,且非常直观

    一个 collection 解决所有事
    txhwind
        25
    txhwind  
       5 天前   ❤️ 1
    map 写前面确实反人类了,像 C# Linq 一样 data["item"].select(x => x["id"]) 感觉自然一点
    TWorldIsNButThis
        26
    TWorldIsNButThis  
       5 天前 via iPhone   ❤️ 1
    python 的 lambda 本来就恶心
    clino
        27
    clino  
       5 天前   ❤️ 1
    要不楼主给一个感觉可读性比较好的写法?
    然后可以弄一个 python 包来支持这种可读性更好的写法,这样至少自己要写的时候可以用。
    TWorldIsNButThis
        28
    TWorldIsNButThis  
       5 天前 via iPhone   ❤️ 1
    @w568w map 从来都只有映射的意思
    DOLLOR
        29
    DOLLOR  
       5 天前 via Android   ❤️ 2
    估计 python 作者不喜欢 lambda 和 fp ,故意把 lambda 和 map 这些设计得非常恶心。
    别的语言都没那么难看。
    比如 js 的 map 就爽多了。
    hj960511
        30
    hj960511  
       5 天前   ❤️ 1
    ChrisFreeMan
        31
    ChrisFreeMan  
       5 天前   ❤️ 1
    所以我现在只用 typescript ,hover 文档一眼就知道了。另外 python 支持 TypedDict https://peps.python.org/pep-0589/
    julyclyde
        32
    julyclyde  
       5 天前   ❤️ 1
    map 和 foreach 其实一码事吧
    就算用 foreach 你也得进去看看到底执行了啥呀
    fsdrw08
        33
    fsdrw08  
       5 天前 via Android   ❤️ 1
    我去年 6 月写了一段 Python map 的代码,现在看回去,已经看不懂这段代码的作用了
    simenet
        34
    simenet  
       5 天前   ❤️ 1
    你都用 python 了 还恶心啥哦
    RangerWolf
        35
    RangerWolf  
       5 天前   ❤️ 1
    op 无需 pua 自己,觉得他恶心不是你的错
    map 我也觉得很反人类,只不过可能没有 op 反感的强度高而已
    我记得 effective python 里面也不推荐使用 map 函数(记错请各位轻拍)
    RangerWolf
        36
    RangerWolf  
       5 天前   ❤️ 2
    应该没记错
    Item 27: Use Comprehensions Instead of map and filter
    lululau
        37
    lululau  
       5 天前   ❤️ 1
    @RangerWolf #35 列表解释不就是 filter(select) + map 吗,就换种写法而已

    这点弯转不过来,建议多做做算法题训练一下
    jim9606
        38
    jim9606  
       5 天前   ❤️ 2
    只针对 python

    我理解 lambda 是做简单调用(单个表达式)的,例如给函数绑定参数这种没啥重用价值的事,复杂需要的应该用命名函数,不想污染命名空间也可以用内部函数,反正要命名。

    另外通常 map/filter/reduce 可以展开为 for..in 循环,而且这种更好按行断点。
    Yuanlaoer
        39
    Yuanlaoer  
       4 天前
    感受,没有客观对错,或者说你感受到的都可以说是“真实的”和“对的”。你觉得厌恶就是厌恶。

    就算你知道还有 100 个人也厌恶,能改变你什么吗?
    galenjiang
        40
    galenjiang  
       4 天前
    map 本来就是需要用读来确认用途的,比较好的做法,结合 pointless 来做,getId = map(lambda x: x["id"]); getId(data['item']),你连什么是函数式编程的门槛都没入,谈不上厌恶...
    Lhcfl
        41
    Lhcfl  
       4 天前
    这个没办法,python 的语法就是丑,毕竟发明人就讨厌 lambda 函数,换 js 的 data["item"].map((x) => x.id) 不好吗
    msg7086
        42
    msg7086  
       4 天前
    我是觉得 Python 语法丑。
    什么 len(),什么 map(),然后还有一堆人绞尽脑汁为这种语法编出几条道理来……
    还有什么 lambda 只能单行这样的限制(
    反正不是我的菜,除非老板摁着我的头让我写,否则还是另请高明吧。
    netabare
        43
    netabare  
       4 天前 via iPhone
    @levelworm 我的理解是这个问题可能比起智商倒不如是语言设计的问题。你也多次提到了「要是他不叫 map 好理解一点」。

    也许换个语言会好很多(不过如果是工作要求就没办法)
    julyclyde
        44
    julyclyde  
       3 天前
    @jim9606 我赞成 38 层的意见
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   963 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 19:05 · PVG 03:05 · LAX 11:05 · JFK 14:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.