【问题标题】:Can I do a reduce on a list comprehension into two lists, based on two values?我可以根据两个值将列表理解缩减为两个列表吗?
【发布时间】:2010-12-27 15:28:38
【问题描述】:

我有以下代码。

sum_review = reduce(add,[book['rw'] for book in books])
sum_rating = reduce(add,[book['rg'] for book in books])
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items

我想要的是这个。

sum_review,sum_rating = reduce(add,([book['rw'],[book['rg']) for book in books])
items = len(books)
avg_review = sum_review/items
avg_rating = sum_rating/items

显然这不起作用。如果没有常规循环,如何解决这种冗余?

【问题讨论】:

    标签: python python-2.5


    【解决方案1】:

    我会避免在这里使用 reduce。对于如此简单的事情,请使用sum:

    sum_review = sum(book['rw'] for book in books)
    sum_rating = sum(book['rg'] for book in books)
    

    在我看来,这个更简单的版本不需要重构来消除冗余。只有两个项目(rwrg)我认为最好保持原样。

    【讨论】:

      【解决方案2】:

      有两种典型的简化代码的方法:

      1. 自上而下:首先获取值,然后用zip(*iterable) 转置它们。这也很酷,因为它只迭代集合一次:

        values = ((book["rw"], book["rg"]) for book in books)
        avg_review, avg_rating = [sum(xs) / len(books) for xs in zip(*values)]
        
      2. 自下而上:创建一个函数来抽象操作:

        get_avg = lambda xs, attr: sum(x[attr] for x in xs) / len(xs)
        avg_review = get_avg(books, "rw")
        avg_rating = get_avg(books, "rg")
        

      【讨论】:

      • +1 回答了这个问题,我同意失去可读性是不值得的。
      • 我不会使用这个,但我接受它,因为它回答了问题。
      【解决方案3】:
      sum_review, sum_rating = reduce(lambda a,b: (a[0] + b[0], a[1]+b[1]), ((book['rw'], book['rg']) for book in books), (0,0) )
      items = len(books)
      avg_review = sum_review/items
      avg_rating = sum_rating/items
      

      (已测试)

      【讨论】:

        【解决方案4】:

        您应该更喜欢清晰而不是优化。在使用 Python 的 3 年中,我只需要分析两次即可发现性能瓶颈。您的原始代码清晰高效。将前两行压缩为一行会损害可读性,并且几乎不会影响性能。

        如果我不得不修改你的代码,它会是这样的:

        avg_review = sum(book['rw'] for book in books) / len(books)
        avg_rating = sum(book['rg'] for book in books) / len(books)
        

        (将五行代码缩减为两行代码,提高了清晰度。)

        【讨论】:

        • 我不明白你为什么认为 OP 完全关心“优化”或“性能”。
        • @Karl Knechtel:他担心两个循环的冗余(隐藏在列表推导中)。他意识到他可以显式地编写一个循环来消除循环两次的需要。 (至少,我是这样解释他的问题的。他可能只关心重复,但我在 StackOverflow 上的许多 Python 问题归结为“我该如何优化这个?”)
        • 这正是我在第一次回复中了解sum后将代码更改为的。是的,我想将两个循环减少到一个,但到目前为止给出的解决方案让我考虑不这样做。
        【解决方案5】:

        我该如何解决这种冗余

        当然是通过制作函数:

        def average_value(items, key):
          values = [x[key] for x in items]
          return sum(items) / len(items)
        
        avg_review, avg_rating = average_value(books, 'rw'), average_value(books, 'rg')
        

        【讨论】:

          猜你喜欢
          • 2023-01-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-14
          • 2021-12-03
          • 2013-07-10
          • 1970-01-01
          相关资源
          最近更新 更多