减少元组列表

2 投票
1 回答
1424 浏览
提问于 2025-04-18 06:25

在我学习Python的过程中,我正在实现一个“牛和水”的游戏。
我已经有了一个可以工作的版本,使用了列表推导式,但我想试试用生成器来解决这个问题,并用reduce()来得到最终结果。

这是我的生成器:

def bullsandcows(given, number):
    for i in range(given.__len__()):
        if given[i] == number[i]:
            yield (given[i], None)
        elif given[i] in number:
            yield (None, given[i])

这是我的reduce实现:

(bulls, cows) = reduce(\
    lambda (bull, cow), (b, c): \
        (bull + 1, cow + 1), bullsandcows(given, number), (0, 0))

在这里,given是用户输入的数字,而number是随机生成的数字,用户需要猜这个数字。

如你所见,这个实现并不是完全可用的,它只是返回了yield生成的元组的计数。

我需要的是替换(bull + 1, cow + 1)的部分,但我不知道该怎么构造这个。

  • number是一个随机生成的数字,比如说:1234
  • given是用户输入的数字,比如说:8241
  • 调用bullsandcows(given, number)的结果应该是:[('2', None), (None, '4'), (None, '1')]
  • reduce的结果应该是:(1, 2),这表示第一个元素中所有非None值的数量和第二个元素中所有非None值的数量

1 个回答

2

如果我理解得没错,你想要统计哪些 bull 不是 None,还有多少 cow 不是 None

reduce(lambda (bcount, ccount), (b, c): (bcount + (b is not None), ccount + (c is not None)),
       bullsandcows(given, number), (0, 0))

这个代码的作用是只有在 bullcow 的值不是 None 的时候,才会增加一个计数器。测试的结果是一个布尔值,布尔值是整数的一种特殊类型,其中 False 等于 0,而 True 等于 1;把一个整数和一个布尔值相加,结果会是另一个整数。

因为你输入的是非空字符串,所以你可以把它简化为:

reduce(lambda (bcount, ccount), (b, c): (bcount + bool(b), ccount + bool(c)),
       bullsandcows(given, number), (0, 0))

我会把 bullsandcows() 改写成:

def bullsandcows(given, number):
    given, number = map(str, (given, number))
    for g, n in zip(given, number):
        if g == n:
            yield (g, None)
        elif g in number:
            yield (None, g)

比如说,使用 zip() 函数来把 givennumber 的数字配对起来。

示例:

>>> def bullsandcows(given, number):
...     given, number = map(str, (given, number))
...     for g, n in zip(given, number):
...         if g == n:
...             yield (g, None)
...         elif g in number:
...             yield (None, g)
... 
>>> given, number = 8241, 1234
>>> list(bullsandcows(given, number))
[('2', None), (None, '4'), (None, '1')]
>>> reduce(lambda (bcount, ccount), (b, c): (bcount + bool(b), ccount + bool(c)),
...        bullsandcows(given, number), (0, 0))
(1, 2)

注意,在函数参数中解包的功能在 Python 3 中被移除了,而 reduce() 这个内置函数也被转移到了库函数中;所以你的代码只能在 Python 2 中运行。

要让它在 Python 3 中工作,你需要导入 functools.reduce(),并调整 lambda 表达式,使其不使用解包:

from functools import reduce

reduce(lambda counts, bc: (counts[0] + bool(bc[0]), counts[1] + bool(bc[1])),
       bullsandcows(given, number), (0, 0))

撰写回答