在Python中使用filter和reduce计算出现次数

2024-04-26 03:25:59 发布

您现在位置:Python中文网/ 问答频道 /正文

c=["pink", "purple", "black", "yellow", "purple", "indego", "white", "peach"]
import random
import collections
def apply(T):
    i = random.randint(0, 7)
    return c[i]
for x in range(1, 50):
    for ch in map(apply, c):
        print(ch)

我试图通过使用filter和reduce函数来计算每个数字的出现次数。

有人能给我指个正确的方向吗?

编辑:为了澄清,我想计算生成某种类型随机数的次数,而不是列表中的次数!


Tags: inimportforrandomch次数collectionsblack
3条回答

首先,你的apply函数忽略了它的参数,这对于你给map的东西来说从来不是一个好兆头。我假设您试图生成一个名为colors的随机颜色列表,然后对其进行计数;您同样可以用生成器替换它。

Filter、reduce等是函数式编程概念,通常通过Python中的列表理解或生成器更好地处理。我会这样做:

c = ["pink", "purple", "black", "yellow", "purple", "indego", "white", "peach"]

import random
colors = [c[random.randrange(len(c))] for _ in range(50)]

# now, to count

# (a) the way you'd actually do it in practice:
from collections import Counter
counts = Counter(colors)

# (b) the way you'd actually do it without the collections module
counts = {}
for x in colors:
    if x not in counts:
        counts[x] = 0
    counts[x] += 1

# (c) doing it with reduce...technically.
def add_to_counter(counter, el):
    counter[el] += 1  # can't actually do this in a lambda...
counts = reduce(add_to_counter, colors, Counter())

你也可以做一些类似于(c)的事情,但是不需要使用Counter类,只需要维护一个元素列表和它们的计数,并在reduce函数中添加它们,但是这只是一个效率更低、更麻烦的版本。

既然你说你已经使用了过滤和减少,我假设这是一个家庭作业。这很愚蠢,因为这些绝对是解决这个问题的错误工具。但是这里有一个非常低效和不可读的方法来使用filter和reduce(还有map)来解决这个问题,这可能和你的老师正在寻找的一样:

from functools import partial
import operator
counts = {}
for x in c:
    counts[x] = reduce(operator.add,
                       map(lambda _: 1, filter(partial(operator.eq, x), colors)),
                       0)

这太可怕了,因为:

  • 要弄清楚发生了什么,而不是上面(a)和(b)的明显性,需要付出很大的努力。
  • 你应该总是在Python中使用sum,而不是reduce(operator.add, ...)
  • 因此,counts[x] = sum(1 for el in colors if el == x)是相同的(坏的)算法,但是可读性要高出一百万倍,启动时间也要短得多。
  • 即使如此,reduce/summap也可以被对len(filter(...))的调用所替代(假设Python 2;在三个函数中,filter返回一个迭代器,因此您必须执行len(list(filter(...))),这是浪费。
  • 它为每种颜色传递一次完整的colors列表,而不是仅传递一次。这使得它不可能在你不知道可能结果的完整列表的情况下使用,而且在所有情况下效率都要低得多。

唯一可能的“优势”是,它包括0计数的任何颜色,没有出现。当然,这对于任何其他解决方案来说都是微不足道的。

我认为这将是最简单的解决办法。它不使用过滤器,但似乎是非常聪明的解决方案

counts = [(colors.count(x), x) for x in set(colors)]

你也可以做一个dict,而不是元组列表。。。取决于您使用的python解释器版本。

@道格

下面可以使用reduce和lambda对列表进行计数:

    c = ["pink", "purple", "black", "yellow", "purple", "indego", "white", "peach", "test"]
    print reduce(lambda x, y: x + 1, c, 0)

注意最后一个reduce()参数是0。

相关问题 更多 >