1

我非常困惑。我正在尝试制作一个遵循以下模式的程序:

Index:    Value:
0         0
1         10
2         1110
3         3110
4         132110
5         1113122110
6         311311222110
...

此模式采用函数的前一个值并表示位数,例如,如果索引 1 为 10,则 2 将表示一个 1 和一个 0 或 1110。

我做了一个函数,它接受字符串的第一个字符并返回该字符在字符串的其余部分中出现的次数。我需要提示索引,然后它会打印出来:

index : digits : english words
 3 : 3110 : three ones. one zero

这是我到目前为止的代码,但我不知道如何解决实际值:

def strHead(s):
   """strHead: String -> String"""
   return s[0]

def strTail(s, run):
  """strTail: String -> String"""
   return s[1:]

def runLenAux(s, c):
""" s = string and c = head of string
"""
    if s == "":
        return 0
    else:
        if strHead(s)== c:
            return 1 + int(runLenAux(strTail(s), c))
        else:
            return 0

编辑:不幸的是,我不能使用任何内置函数,如 .append 或 len() 我什至不能使用列表。:( 如果给定索引,有没有办法将我的函数 runLenAux(s, c) 合并到查找值中?

4

3 回答 3

3

这主要是为您编写的,其形式itertools.groupby采用可迭代(在您的情况下为字符串)并将唯一元素分组。它提供了一个生成器(如果您不熟悉它们,可以将其视为一个可以循环的列表),其中每一对是原始可迭代的值,然后是所有这些值。

因此,例如:

>>> s = str(1113122110)
>>> groupby(s)
<itertools.groupby at 0x1044be5d0>

让我们列出它们以查看它们:

>>> [(n, list(c)) for n, c in groupby(s)]
[('1', ['1', '1', '1']),
 ('3', ['3']),
 ('1', ['1']),
 ('2', ['2', '2']),
 ('1', ['1', '1']),
 ('0', ['0'])]

要将其转换为您想要的格式,您确实需要每个辅助列表的长度:

>>> [(len(list(c)), n) for n, c in groupby(s)]
[(3, '1'), (1, '3'), (1, '1'), (2, '2'), (2, '1'), (1, '0')]

让我们制作长度字符串:

>>> [(str(len(list(c))), n) for n, c in groupby(s)]
[('3', '1'), ('1', '3'), ('1', '1'), ('2', '2'), ('2', '1'), ('1', '0')]

要获得下一个数字,您将需要join所有这些。为此,请“链接”它们:

>>> from itertools import chain
>>> ''.join(chain(*[(str(len(list(c))), n) for n, c in groupby(s)]))
'311311222110'

当然,如果您不想只打印它,您可能希望在末尾有一个整数:

>>> int(''.join(chain(*[(str(len(list(c))), n) for n, c in groupby(s)])))
311311222110

要获取英文描述符,我会使用 dict 来获取英文单词:

nwords = {'0': zero, '1': 'one', '2': 'two', '3': 'three'} # etc.
for c, n in [(str(len(list(c))), n) for n, c in groupby(s)]:
    print "{c} {n}{p}".format(p='' if c=='1' else 's', c=nwords[c], n=nwords[n])

打印:

three ones
one three
one one
two twos
two ones
one zero

我会让你把这些部分放在一起,得到一个需要索引并递归计算以前的答案来给出最终答案的东西。

于 2013-09-29T23:32:15.523 回答
3

首先,这些:

def strHead(s):
   """strHead: String -> String"""
   return s[0]

def strTail(s, run):
  """strTail: String -> String"""
   return s[:]

他们没有做任何有用的事情;第一个返回项目 0,第二个只返回字符串。查克他们。

然后

def runLenAux(s, c):
    if s == "":
        return 0
    else:
        if strHead(s)== c:
            return 1 + int(runLenAux(strTail(s), c))
        else:
            return 0

现在有一个明显的问题。当它们充其量是数字列表时,您将它们视为数字。但是其他时候,您将它们视为字符串。

让我们将它们视为列表,因为这样更明显。

所以:

def runLenAux(s, c):

s和是什么c?不知道。我想这是为了获得下一个值,所以做一个[1, 0] → [1, 1, 1, 0]映射。所以让它列出一个清单:

def look_and_say(term):
    """Looks at and says a term."""

->在 Python 3 中,您可以对函数进行注释,而不是做有趣的事情。通过向他们展示这个半隐晦的事实来打动您的同龄人!

def look_and_say(term: "[int]") -> "[int]":
    """Looks at and says a term."""

在这里,我"[int]"用来表示“a listof ints”。

所以,进入下一部分:

    if s == "":
        return 0

天哪!你打算使用递归吗?!这太多了!我们不是这里的Haskell

好的,从顶部开始。我们想要遍历,记录我们见过多少相同的项目,是吗?所以我们可以做一个像这样的循环:

for item in term:
    count how many are the same
    if different, break

(这听起来像是以前做过的事情。嗯,它已经完成了。它被称为itertools.groupby。不过,让我们假装你不知道。)

count = 0
match = None
for item in term:
    # If this isn't the same we should stop counting
    if match != item:
        do_something_with_count_and_match

        # Start again from this item
        count = 1
        match = item

    # If this is the same we should continue counting
    else:
        count = count + 1

这看起来不错!

放什么do_something_with_count_and_match?好吧,让我们保留一份清单,把东西放进去,然后把我们的结果放在那里

# This is what we're building
next_term = []

...
for item in term:
    ...
    if match != item:
        # Say "One One" or "Two Threes" or "Three Ones", etc.
        next_term.append(count)
        next_term.append(match)

        # Start again from this item
        count = 1
        match = item
    ...

那么,它运行了吗?

def look_and_say(term: "[int]") -> "[int]":
    """Looks at and says a term."""
    # This is what we're building
    next_term = []

    count = 0
    match = None
    for item in term:
        # If this isn't the same we should stop counting
        if match != item:
            # Say "One One" or "Two Threes" or "Three Ones", etc.
            next_term.append(count)
            next_term.append(match)

            # Start again from this item
            count = 1
            match = item

        # If this is the same we should continue counting
        else:
            count = count + 1

look_and_say([0])
#>>> 

嗯……没有输出。

啊,我们忘记returnnext_term

def look_and_say(term: "[int]") -> "[int]":
    ... # All that stuff

    return next_term

look_and_say([0])
#>>> [0, None]

嗯..那不好。我们需要确保我们没有计算None占位符match

def look_and_say(term: "[int]") -> "[int]":
    ...
    for item in term:
        ...
        if match != item:
            if match is not None:
                next_term.append(count)
                next_term.append(match)
            ...
    ...

我们还需要添加最后一部分,即使它不会触发else(循环将停止):

def look_and_say(term: "[int]") -> "[int]":
    ...
    for item in term:
        ...

    if match != item:
        if match is not None:
            next_term.append(count)
            next_term.append(match)

    return next_term

那就试试吧:

def look_and_say(term: "[int]") -> "[int]":
    """Looks at and says a term."""
    # This is what we're building
    next_term = []

    count = 0
    match = None
    for item in term:
        # If this isn't the same we should stop counting
        if match != item:
            # Say "One One" or "Two Threes" or "Three Ones", etc.
            if match is not None:
                next_term.append(count)
                next_term.append(match)

            # Start again from this item
            count = 1
            match = item

        # If this is the same we should continue counting
        else:
            count = count + 1

    if match is not None:
        next_term.append(count)
        next_term.append(match)

    return next_term

look_and_say([0])
#>>> [1, 0]

look_and_say([1, 0])
#>>> [1, 1, 1, 0]

look_and_say([1, 1, 1, 0])
#>>> [3, 1, 1, 0]

是的!

我这样做是为了向您展示编程不是魔术。你只需要不断尝试和应用你所知道的。

我个人会这样实现它:

from itertools import groupby

# What we just implemented
def look_and_say(string):
    for k, v in groupby(string):
        yield sum(1 for _ in v)
        yield k

list(look_and_say([0]))
#>>> [1, 0]

list(look_and_say([1, 0]))
#>>> [1, 1, 1, 0]

list(look_and_say([1, 1, 1, 0]))
#>>> [3, 1, 1, 0]

但这只是因为我知道groupby

于 2013-09-29T23:47:13.900 回答
1

虽然 itertools.groupby() 很容易,但有时将一些东西组合在一起很有趣

def foo(seed = '0', nbr_of_indexes = 6):
    """returns a formatted string matching pattern described by OP
    """
    def groups(s, match = None, count = 0, result = ''):
        """count consecutive matches

        returns str
        """
        # recursion base case, no more s
        if not s:
            result += (str(count) + match)
            return result
        # initialize match
        if not match:
            match = s[0]
        if s[0] == match:
            count += 1
        else:
            result += (str(count) + match)
            match = s[0]
            count = 1
        return groups(s[1:], match, count, result)
    result = [(0,'0')]
    for index in xrange(1, nbr_of_indexes + 1):
        result.append((index, groups(seed)))
        seed = result[-1][1]
    return ''.join(['{}\t{}\n'.format(*thing) for thing in result])    

>>> print foo()
0   0
1   10
2   1110
3   3110
4   132110
5   1113122110
6   311311222110

>>>

编辑:更改 groups() 以对整个字符串进行分组和计数,而不仅仅是第一项

于 2013-09-30T02:25:38.263 回答