如何让一个函数在列表上迭代两次,从中断它的位置?

时间:2016-10-01 17:41:35

标签: python

我正在制作一个Facebook Messenger机器人,它返回指定停靠点的公交车次数。到目前为止,机器人工作正常,但Facebook不允许机器人发送的消息超过320个字符。通常情况下,机器人只能显示前5个左右而不超过此限制,这在非常繁忙的停留时间不够好。

我有一个if语句,如果停止次数多于此值,则只显示前五个结果,然后将结果传递给机器人的send_message函数。

我正在寻找一种方法,可以在5个单独的块中获取大型停止列表的结果,并在发送第一条消息后让机器人从停止的位置开始。我目前的代码如下:

if len(info["results"]) > 5:
    while i < 5:
        n.append("Route:" + " " + str(info['results'][i]['route']) + " " + "to" + " " + str(info['results'][i]['destination']) + "\n" + "Due:" + " " + str(info["results"][i]["duetime"]) + " " + "minutes." + "\n")
        i = i + 1
else:
    while i < len(info["results"]):
        n.append("Route:" + " " + str(info['results'][i]['route']) + " " + "to" + " " + str(info['results'][i]['destination']) + "\n" + "Due:" + " " + str(info["results"][i]["duetime"]) + " " + "minutes." + "\n")
        i = i + 1

return '\n'.join(str(x) for x in n)

底部的return语句是传递给send_message函数的内容。有什么方法可以实现多重消息方法吗?

5 个答案:

答案 0 :(得分:4)

您可以通过在下面的代码中写generator function chunks()来轻松完成此操作:

info = {'results': [
            {'route': 1, 'destination': 'DestA', 'duetime': '10'},
            {'route': 2, 'destination': 'DestB', 'duetime': '20'},
            {'route': 3, 'destination': 'DestC', 'duetime': '30'},
            {'route': 4, 'destination': 'DestD', 'duetime': '40'},
            {'route': 5, 'destination': 'DestE', 'duetime': '50'},
            {'route': 6, 'destination': 'DestF', 'duetime': '60'},
            {'route': 7, 'destination': 'DestG', 'duetime': '70'},
            {'route': 8, 'destination': 'DestH', 'duetime': '80'},
            ],
       }

def chunks(info, n):
    results = info['results']
    for i in range(0, len(results), n):
        chunk = [
            'Route: {} to {}\nDue: {} minutes.\n'.format(
                result['route'], result['destination'], result["duetime"])
                    for result in results[i:i+n]]
        yield '\n'.join(chunk)

for i, chunk in enumerate(chunks(info, 5), 1):
    print('== CHUNK {} ==\n{}'.format(i, chunk))

输出:

== CHUNK 1 ==
Route: 1 to DestA
Due: 10 minutes.

Route: 2 to DestB
Due: 20 minutes.

Route: 3 to DestC
Due: 30 minutes.

Route: 4 to DestD
Due: 40 minutes.

Route: 5 to DestE
Due: 50 minutes.

== CHUNK 2 ==
Route: 6 to DestF
Due: 60 minutes.

Route: 7 to DestG
Due: 70 minutes.

Route: 8 to DestH
Due: 80 minutes.

答案 1 :(得分:1)

以下是使用generator和yield关键字 -

实现此目的的示例代码
def splitter(long_mess) :
        split_mess = ""
        for index in xrange(len(long_mess)) :
                if index>0 and index%5==0 :
                        yield split_mess
                        split_mess = ""
                split_mess += str(long_mess[index]) #replace with the n.append line
        yield split_mess

input = "This is a really long message"
ans = splitter(input)
for i in ans :
        print i #replace with send_message(i)

输出:

This 
is a 
reall
y lon
g mes
sage

答案 2 :(得分:0)

下面是一个示例代码,它列出了包含大约5个停靠点的信息的列表。然后,您可以在循环中调用send_message

def split_into_pairs_of_5(info)
    outer = []
    inner = []
    for x in range(len(info["results"])):
        if x % 5 == 0 and inner:
            outer.append(inner)
            inner = []

        inner.append("Route:" + " " + str(info['results'][i]['route']) + " " + "to" + " " + str(info['results'][i]['destination']) + "\n" + "Due:" + " " + str(info["results"][i]["duetime"]) + " " + "minutes." + "\n")

    if inner:
        outer.append(inner)
        inner = []

    return outer


result = split_into_pairs_of_5(info)

for i in info:
    send_message('\n'.join(str(x) for x in i))

答案 3 :(得分:0)

我的方法使用itertools.groupby()将记录分组为5(或任何正数)。在您的帖子中,您没有显示send_message来电的姓名,因此我只是自己命名:get_info

import itertools

def show_rec(rec):
    output = 'Route: {route} to {destination}, due in {duetime} minutes'.format(**rec)
    return output

def get_info(group_size=5):
    # Do something to get info
    counter = itertools.count()
    for _, group in itertools.groupby(info['results'], key=lambda v: next(counter) // group_size):
        yield '\n'.join(show_rec(r) for r in group)

# Here is inside function send_message
for output in get_info(group_size=5):
    print output
    print

讨论

  • 对我来说,第一项业务不是如何解决这个问题,而是如何以一种漂亮,干净,易于理解的方式呈现记录,为此,我创建了函数show_rec做这份工作
  • get_info实际上是一个生成器,而不是常规函数(请参阅yield关键字)
  • get_info内,我借助group_size函数将itertools.groupby组中的记录分组,counter函数本身就是一个生成器。
  • 请注意next(counter)是一个生成器对象,其中next(counter) // group_size将产生0,1,2,3,4,5,6,7,8 ......表达式{{1}将为group_size=5产生0,0,0,0,1,1,1,1,1,2,2 ......,这就是我们用来对记录进行分组的内容。

答案 4 :(得分:0)

您可以使用range(或Python 2.7中的xrange)生成器函数,如下所示:

info = {'results': [
    {'route': 1, 'destination': 'DestA', 'duetime': '1'},
    {'route': 2, 'destination': 'DestB', 'duetime': '2'},
    {'route': 3, 'destination': 'DestC', 'duetime': '3'},
    {'route': 4, 'destination': 'DestD', 'duetime': '4'},
    {'route': 5, 'destination': 'DestE', 'duetime': '5'},
    {'route': 6, 'destination': 'DestF', 'duetime': '6'},
    {'route': 7, 'destination': 'DestG', 'duetime': '7'},
    {'route': 8, 'destination': 'DestH', 'duetime': '8'},
]}


def iter_with_chunks(seq, chunk_size):
    for index in range(0, len(seq), chunk_size):
        yield seq[index: index + chunk_size]


for count, chunk in enumerate(iter_with_chunks(info["results"], 5), 1):
    print("== CHUNK {count} ==".format(count=count))
    for item in chunk:
        output = 'Route: {route} to {destination},\n' \
                 'due in {duetime} minutes\n'.format(**item)
        print(output)

输出:

== CHUNK 1 ==
Route: 1 to DestA,
due in 1 minutes

Route: 2 to DestB,
due in 2 minutes

Route: 3 to DestC,
due in 3 minutes

Route: 4 to DestD,
due in 4 minutes

Route: 5 to DestE,
due in 5 minutes

== CHUNK 2 ==
Route: 6 to DestF,
due in 6 minutes

Route: 7 to DestG,
due in 7 minutes

Route: 8 to DestH,
due in 8 minutes