【问题标题】:How could one reduce the usage of helper functions in lambda expressions?如何减少 lambda 表达式中辅助函数的使用?
【发布时间】:2021-11-06 22:44:18
【问题描述】:

在这个例子中,我从一个集合中取出字母并将它们附加到一个字典中,其中字母成为键,文字 1 成为每一对的值。

def base_dict_from_set(s):
    return reduce(lambda d,e : addvalue(1, e, d), s, dict())


def addvalue(value, key, d):
    d[key] = value
    return d
>>> base_dict_from_set(set("Hello World!".lower()))
{'o': 1, '!': 1, 'l': 1, 'd': 1, 'w': 1, ' ': 1, 'r': 1, 'e': 1, 'h': 1}

我想知道我是否可以以某种方式摆脱“addvalue”辅助函数并添加元素并在 lambda 函数本身中引用修改后的字典。

addvalue 本身的例程对我来说非常简单,所以我更喜欢看起来像这样的东西:

def base_dict_from_set(s):
    reutrn reduce(lambda d,e : d[e] = 1, s, dict())

我在 python 方面没有很多经验,我是从函数式编程的角度来的。我的目标是了解 python 的功能,但我太缺乏经验,无法正确表达和谷歌搜索我正在寻找的内容。

【问题讨论】:

  • 我喜欢问题标题中包含“减少”一词。

标签: python data-structures lambda functional-programming one-liner


【解决方案1】:

您要做的是为什么dict.fromkeys 存在:创建一个将每个键映射到相同常量值的字典。

>>> dict.fromkeys("Hello World!".lower(), 1)
{'h': 1, 'e': 1, 'l': 1, 'o': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1, '!': 1}

无需先将字符串转换为set,因为任何重复的内容都会被以下出现的内容覆盖。

(如果常量值是可变的,您应该使用 dict 推导来确保每个键都获得其自己的可变值,而不是每个键共享对相同可变值的引用。)

【讨论】:

    【解决方案2】:

    您可以使用 dict comprehension 获得相同的结果:

    {l: 1 for l in set("Hello World!".lower())}
    

    【讨论】:

    • 仅当他们不想真正计算出现次数时
    • “文字 1 变成了值” — 是的,听起来他们没有。
    • 坦率地说,我们都不知道 OP 真正想要做什么。我认为我们想出了几个不同的答案真是太好了。
    【解决方案3】:

    要准确回答所提出的问题,是的,您可以通过将 addvalue(1, e, d) 替换为 {**d, e:1} 来摆脱 addvalue。

    尽管如此,您的代码仍然有问题。它不计算出现次数,而是为字符串中的每个字母创建一个 key: 1 的字典,它应该创建一个 key: number_of_occurences 的字典来实现这一点,您应该将 addvalue(1, e, d) 替换为 {**d, e: 1 + (d[e] if e in d else 0)} 并且不将字符串转换为set 因为它消除了重复项

    【讨论】:

    • 别担心那个缺陷;尽管听起来很愚蠢,但实际上是故意的。不过,您的解决方案绝对非常好,感谢您抽出宝贵的时间! :)
    • 你不应该以某种方式调用你的函数,表明它们做了他们不做的事情:)
    • @Nez 现在我很好奇。你的是目的是什么?
    • @Vulwsztyn 是的,你是对的。可能有点误导。我很好奇在哪里可以查看您介绍的语法,我不知道我在看什么
    • @Nez 还注意到 python 对于函数式编程来说是一种糟糕的语言;通常首选带有迭代的解决方案(可能还有itertools)。
    【解决方案4】:

    当您的目标是将输入集合中的每个项目(字符串中的字母)转换为输出集合(键/值对,其中键是字母和值是一个常数),相互独立。

    在我看来,reduce 用于需要对序列中的项目执行操作并考虑所有先前项目的情况(例如,在计算值的总和时)。

    所以在我看来,在功能风格中,在这里使用map 比reduce 更合适。 Python 支持这一点:

    def quant_dict_from_set(s):
        return dict(map(lambda c: (c, 1), s.lower()))
    

    map 将字符串转换为键/值对,dict 构造函数将这些对收集到字典中,同时消除重复键。

    但更惯用的方法是使用dictionary comprehension 或dict.fromkeys constructor。

    【讨论】:

    • 如果他真的想计算出现次数,使用 reduce 会很有意义
    【解决方案5】:

    Hacky 且难以阅读,但与您尝试编写的 lambda 最接近,并且希望具有教育意义:

    >>> f = lambda d, e: d.__setitem__(e, 1) or d
    >>> d = {}
    >>> output = f(d, 42)
    >>> output
    {42: 1}
    >>> output is d
    True
    

    使用__setitem__ 可以避免= 分配。

    __setitem__ 返回None,因此表达式d.__setitem__(e, 1) or d 的计算结果始终为d,由lambda 返回。

    【讨论】:

    • 哎呀,IMO 实现这一目标的更好方法在我的回答中
    • @Vulwsztyn 我的答案中的代码不应该被使用。这纯粹是教育性的。
    • 我的意思是d.__setitem__(e, 1) or d 相当于{**d, e: 1}
    • @Vulwsztyn 啊,我明白了。是的,这很聪明!
    • @Vulwsztyn 但是,答案并不严格等价。你的解决方案返回一个 new 字典,我的改变了输入字典。
    【解决方案6】:

    您可以使用collections.Counter,这是dict 的子类,专门用于计算元素的出现次数。

    >>> import collections
    
    >>> collections.Counter('Hello, World!'.lower())
    Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ',': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1, '!': 1})
    
    >>> collections.Counter(set('Hello, World!'.lower()))
    Counter({'w': 1, 'l': 1, 'r': 1, ',': 1, 'h': 1, 'd': 1, 'o': 1, 'e': 1, ' ': 1, '!': 1})
    

    请注意Counter 是合适的,如果你想对元素进行计数,或者如果你想将值初始化为常量 1。如果你想将值初始化为另一个常量,那么 Counter 将不是解决方案,并且你应该使用dictionary comprehension 或dict.fromkeys constructor。

    【讨论】:

    • OP 不计算元素,只使用常量值 dict 作为集合的替换。
    • @chepner 这不是我在做什么吗?
    • 设置一个常数值和计算你已经知道是不同的东西之间有一个(细微的)区别。
    • @chepner 显然这种差异是如此微妙,以至于我没有看到它。你能解释一下吗?
    • 将addvalue 的第一个参数从 1 更改为其他任何值。
    猜你喜欢
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    • 2019-06-26
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    相关资源
    最近更新 更多