【问题标题】:Python -- list comprehension with try/exception and nested conditionalPython——带有try/exception和嵌套条件的列表理解
【发布时间】:2014-01-18 16:36:45
【问题描述】:

此代码应该在 O(n) 线性时间内找到列表的模式。我想把它变成一个列表理解,因为我正在自学 Python,并且正在努力提高我的列表理解技能。
这些内容很丰富,但并没有真正回答我的问题:

Convert nested loops and conditions to a list comprehension

`elif` in list comprehension conditionals

Nested list comprehension equivalent

我遇到的问题是嵌套 if 和 try/except。我确信这是一个简单的问题,所以初级 Python 程序员可能很快就会有答案。

def mode(L):
    # your code here
    d = {}; mode = 0; freq = 0
    for j in L:
        try:
            d[j] += 1
            if d[j] > freq:
                mode = j; freq = d[j]
        except(KeyError): d[j] = 1
    return mode

请注意,L 参数是一个整数列表,如下所示:

L = [3,4,1,20,102,3,5,67,39,10,1,4,34,1,6,107,99]

我在想这样的事情:

[try (d[j] += 1) if d[j] > freq (mode = j; freq = d[j]) except(KeyError): d[j] = 1 for j in L]

但我没有足够的胶带来修复语法与那个东西的关系有多糟糕。

【问题讨论】:

  • import this。阅读 1-7。这些是我从 Python 中学到的最好的教训。

标签: python python-2.7 try-catch list-comprehension conditional-statements


【解决方案1】:

我知道您正在学习理解,但您可以使用默认字典或计数器来做到这一点。

import collections
def mode(L):
    # your code here
    d = collections.defaultdict(lambda: 1); mode = 0; freq = 0
    for j in L:
            d[j] += 1
            if d[j] > freq:
                mode = j; freq = d[j]
    return mode

更好的是,当您不想学习理解时:

import collections
def mode(L):
    collections.Counter(L).most_common(1)[0][0]

【讨论】:

  • 计数器是问题的正确答案。 DefaultDict 同样麻烦。点赞。
  • 如何通过列表理解来做到这一点?接受的答案不反映问题。
【解决方案2】:

虽然在列表理解中可能无法直接执行此操作,但也没有理由这样做。当您实际检索结果时,您只想检查错误。因此,您真的想使用 generator 而不是列表推导式。

语法大致相同,只是使用括号而不是括号,所以你可以这样做:

generator = (do something)
try:
    for thing in generator
except KeyError:
   etc...

也就是说,您真的不想为您的特定应用程序执行此操作。您想使用计数器:

from collections import Counter
d = Counter(L)
mode = Counter.most_common(1)[0]

【讨论】:

    【解决方案3】:

    您不能将try: except: 合并到列表理解中。但是,您可以通过重构为 dict 理解来绕过它:

    d = {i: L.count(i) for i in L}
    

    然后您可以在单独的测试中确定最大值和对应的键。但是,这将是O(n**2)

    【讨论】:

      【解决方案4】:

      不能在列表理解中使用try-except 表达式。

      引用this answer:

      无法在列表推导中处理异常,因为列表推导是一个包含其他表达式的表达式,仅此而已(即,没有语句,只有语句可以捕获/忽略/处理异常)。

      编辑 1:

      除了使用try-except 子句之外,您还可以使用字典中的get 方法:

      def mode(L):
          d = {}
          mode = 0
          freq = 0
          for j in L:
              d[j] = d.get(j, 0) + 1
              if d[j] > freq:
                  mode = j
                  freq = d[j]
          return mode
      

      来自Python docs

      get(key[, default]):如果key在字典中,则返回key的值,否则返回默认值。如果未给出默认值,则默认为 None,因此此方法永远不会引发 KeyError。

      编辑 2:

      这是我的列表理解方法,效率不高,仅供娱乐:

      r2 = max(zip(L, [L.count(e) for e in L]), key = lambda x: x[1])[0]
      

      【讨论】:

      • 我想你想要d[j] = d.get(j, 0) + 1,默认是零而不是一。
      • 您能否发布您的解决方案的列表理解? LC 确实是我正在努力提高技能的内容,也是我最初发布的原因。
      • 我对列表理解不太了解,但我想不出用列表理解的方式来做到这一点(我的意思是你给出的代码的类似方式)。相反,我尝试了另一种解决方案,但不是最有效的。见编辑。
      【解决方案5】:

      由于您要查找最常出现的值,因此使用max 是一种简单的方法:

      def mode(L):
         return max(L, key=L.count)
      

      这比建议使用collections.Counter(它是O(N^2) 而不是O(N))的其他答案的效率要低一些,但对于一个中等大小的列表来说,它可能已经足够快了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-17
        • 2020-05-29
        • 1970-01-01
        • 2019-06-07
        • 2022-11-07
        • 1970-01-01
        • 2013-05-10
        • 2021-12-22
        相关资源
        最近更新 更多