【问题标题】:Finding years without a repeating digit in python在python中查找没有重复数字的年份
【发布时间】:2015-05-11 07:06:32
【问题描述】:

我正在尝试查找最近 5 年的不重复数字,但我不断收到错误 'int' object has no attribute '__getitem__'

这是我的代码,到目前为止 - 我无法弄清楚它有什么问题。任何关于如何解决它的解释表示赞赏。

def find_year():
    start = 2015
    years = []
    while len(years) < 5:
        if start[0] == start[1]:
            return False
        elif start[0] == start[2]:
            return False
        elif start[0] == start[3]:
            return False
        elif start[1] == start[2]:
            return False
        elif start[1] == start[3]:
            return False
        elif start[2] == start[3]:
            return False
        else:
            years.append(start)
            start -= 1
     else:
          print years

 find_year()

【问题讨论】:

  • 当你有 N 个项目的集合并且想要测试它们都是不同的,那么不要进行 N(N-1)/2 不必要的相等测试,只需将它们分配给一个 set/dict /tuple/list 并测试它的长度是 == N。dict/set 是你的朋友,它有 O(1) 的查找时间,而不是 O(n) 的 list/tuple 或 O(log2 N) 的二叉树.

标签: python digits repeat


【解决方案1】:

您假设您可以索引 ([]) 一个整数以从中获取一个数字,但这不是您可以在 Python 中使用整数做的事情。您可以做的是将整数转换为字符串,然后您可以索引字符串以从中获取字符:

>>> year = 2015
>>> year_as_string = str(year)
>>> year_as_string[0]
'2'

错误消息中提到属性__getitem__ 的原因是因为year[0] 基本上扩展为year.__getitem__(0)Info on __getitem__.

我还建议在较小的部分中解决这个问题。与其试图一次解决整个问题,不如先编写一个函数,该函数需要 one 年,如果没有任何重复数字,则返回 True,否则返回 False。然后,当您完成该工作后,您可以编写另一个函数,在循环中调用第一个函数以获得您需要的五个结果。

有几个很好的方法可以解决完整的问题:

列表理解:

>>> [y for y in range(2015, 0, -1) if len(set(str(y))) == 4][0:5]
[2015, 2014, 2013, 1987, 1986]

迭代器:

from itertools import islice
>>> list(islice(filter(lambda y: len(set(str(y))) == 4, range(2015, 0, -1)), 5))
[2015, 2014, 2013, 1987, 1986]

列表推导更简单,但工作量更大(它会尝试该范围内的所有年份,只丢弃除前五年之外的所有年份);迭代器版本不是那么简单,但(在 Python 3 中)只做它需要做的工作。

【讨论】:

  • 这可以正确诊断 OP 代码的问题。
【解决方案2】:

这可能有效,试试吧:

    >> from collections import Counter

    >> year = 2015
    >> list = map(int, str(year))
    >> counts = Counter(list)
    >> counts
      Counter({0: 1, 1: 1, 2: 1, 5: 1})
    >>Counter(list).values()
     [1,1,1,1]

最后一种方法将计算年份中每个数字的出现次数。这应该更有效率。 现在,如果您想知道是否有重复的数字,请使用此post

>> import bisect

>> bisect.bisect(Counter(list).values(), 1)
4

任何小于 4 的值都意味着有一个数字出现多次。

【讨论】:

  • Umm...collections.Counter 在这里似乎有点矫枉过正 - 只需通过 set 运行数字并检查它与输入的长度相同。 year = 2015; str_year = str(year); if len(str_year) == len(set(str_year)) # no repeated digits
【解决方案3】:

这是一个带有列表理解的单行:

[year for year in range(2015, 1915, -1) if len(set(str(year)))==4] [0:5]

[2015, 2014, 2013, 1987, 1986]

您可以使用len(set(str(year)))==4 测试是否有重复数字。 range(2015, 1915, -1) 限制了我们需要测试的年数。 然后我们将结果用 [0:5] 分割,取前五年这样的年份(从 2015 年开始按降序排列)。

【讨论】:

  • Doh,它需要 len( set (str(year)))==4 。谢谢
【解决方案4】:

问题是您无法使用[] 索引符号访问整数的数字。将其转换为数字序列的一种简单方法,以及检查重复项的一种简单方法是将该序列转换为set 并检查集合的长度是否与位数相同,如果有任何重复,则不会 - 请参阅此 answer 到另一个相关问题。

下面的代码会从起始年份开始查看之前和未来的年份。它还会检查起始年份,但从您的问题中不清楚它是否应该这样做。

def has_dup_digits(year):
    """ Check if integer year has any repeated digits.
    """
    digits = str(year)
    return len(digits) != len(set(digits))

def find_years(start_year):
    """ Find the 5 years closest to the starting year without repeated digits.
    """
    years = []
    if not has_dup_digits(start_year): # check start year
        years.append(start_year)
    delta = 1
    while len(years) < 5:
        if not has_dup_digits(start_year+delta):
            years.append(start_year+delta)
        if len(years) >= 5:
            break
        if not has_dup_digits(start_year-delta):
            years.append(start_year-delta)
        delta += 1

    print(sorted(years))

find_years(2015)  # --> [2013, 2014, 2015, 2016, 2017]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2018-08-16
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    相关资源
    最近更新 更多