【问题标题】:Reduce list of tuples减少元组列表
【发布时间】:2014-07-01 05:45:14
【问题描述】:

作为我学习 Python 之旅的一部分,我正在实现 Bulls and Cows。
我有一个使用列表理解的工作实现,但我认为使用生成器和reduce()-ing 最终结果可能是一个很好的解决方案。

所以我有我的发电机:

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 是随机生成的数字供用户猜测。

如您所见,这并不完全是一个有效的实现,它只会返回 yielded 元组的计数。

我需要替换(bull + 1, cow + 1),我不知道如何构造它。

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

【问题讨论】:

  • len(given) 更清晰时不要使用.__len__(),当可以使用zip() 时不要使用range()
  • 你是对的,解决了这个问题。 似乎忽略bullsandcows 的输出。结果始终是一个包含生成器结果数量的二元素元组
  • 您忽略了 lambda 中的 (b, c) 元组。
  • 没错,这也是我的问题:)
  • 我不清楚输入是什么,你期望什么输出。

标签: python tuples reduce


【解决方案1】:

如果我理解正确的过程,你想数一下bulls不是None,有多少cows不是None

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

仅当bullcow 的值不是None 时,才会增加计数器。测试产生一个布尔值,它是int 的子类,带有False == 0True == 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))

【讨论】:

  • elif g in str(number):
  • @mtadd: 正在解决这个问题。 :-)
  • 谢谢!这完全解决了我的问题。我希望我可以通过解释我如何以及为什么改进我的代码来给你额外的一票。
猜你喜欢
  • 1970-01-01
  • 2014-12-04
  • 2023-03-14
  • 1970-01-01
  • 2017-09-11
  • 2018-10-01
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多