【问题标题】:Comparing Index Values in Python so that I'm Not Constantly Repeating If Statements比较 Python 中的索引值,这样我就不会不断重复 If 语句
【发布时间】:2018-08-30 01:35:33
【问题描述】:

我正在使用 Python 开发一个应用程序,该应用程序采用程序提供的列表并尝试处理文本以进行隐藏式字幕。我正在使用 IBM Watson 转录音频文件,然后返回一个带有转录单词的 JSON 和一个记录每个单词开始时间和结束时间的时间戳。这是该数据的外观的一个小示例。 (注意:我已经简化了 JSON 响应,因此我只突出显示适用于此问题的数据部分)

section = [
    ['for', 5.77, 5.92],
    ['the', 5.92, 6.03],
    ['longest', 6.03, 6.53],
    ['time', 6.53, 7.01],
    ['only', 7.23, 7.56],
    ['a', 7.56, 7.64],
    ['handful', 7.64, 8.2],
    ['of', 8.2, 8.3],
    ['people', 8.3, 8.72],
    ['would', 8.72, 8.88],
    ['know', 8.88, 9.01],
    ['the', 9.01, 9.14],
    ['data', 9.14, 9.56],
    ['that', 9.59, 9.73],
    ['was', 9.73, 9.84],
    ['collected', 9.84, 10.39],
    ['by', 10.39, 10.55],
    ['a', 10.55, 10.63],
    ['specific', 10.63, 11.18],
    ['application', 11.18, 11.91]
]

我只对'section'中每个列表的单词(0-index0和开始时间(1-index)感兴趣。

对于隐藏式字幕,我的目标是每 2.5 秒捕获一组单词,并且只标记该组中第一个单词的时间戳。因此,在上面提供的示例中,提供的第一个索引将是我的“零标记”,并且在 2.5 秒时间范围内跟随的每个单词都将被收集到一个短语中。之后的任何数据都将遵循相同的逻辑——对于所有数据,将彼此相距在 2.5 秒内的单词分组,并标记集合中第一个单词的时间戳。

但是,由于我无法预测文件的持续时间,也无法预测 Watson 将如何转录它们 - 我很难找出在 2.5 秒要求下处理识别单词组的最佳方法。

这是我写的:

    # use the tag variable to identify the start time of the
    # first word outside of 2.5 seconds
    tag = 0

    # use the first index's start time as the benchmark for 2.5 second duration
    benchmark = section[0][1]

    for i in range(len(section)):
        if abs(benchmark - section[i][1]) < 2.5:
            # do stuff
            foo(bar)

            # update tag variable to identify first start time
            # for word outside of 2.5 seconds.  This will
            # continue to update until the if statement is no longer true.
            if (i + 1) < len(section):
                tag = section[i + 1][1]

        else:
            # use tag to create new benchmark
            benchmark = tag
            if abs(benchmark - section[i][1]) < 2.5:
                # do stuff

我苦苦挣扎的地方是,无论转录时间有多长,我都必须继续以这种方式编写函数——这似乎是一系列无穷无尽的潜在 if 语句。换句话说,我仍然需要处理那些不在前 2.5 秒、第二组 2.5 秒内的单词,以此类推。我觉得应该有一个更雄辩和有效的方式来做到这一点。

我的目标是最终处理文本,使其看起来与我在下面列出的内容相似,但无论列表/时间框架有多长都可以工作。

['for the longest time only a handful of', 5.77],
['people would know the data that was collected by a specific', 8.3],
['application', 11.18]

我们将不胜感激任何帮助、指导、建议等。谢谢!

【问题讨论】:

    标签: python python-3.x list conditional


    【解决方案1】:

    这是一种迭代列表中 2.5 秒间隔并输出短语的方法。它是否满足您的需求?

        start = section[0][1]
        end = section[-1][1]
    
        for mark in range(0, int((end-start)/2.5)+1):
            phrase = [(x[0],x[1]) for x in section if int((x[1]-start)/2.5)==mark]
            print([' '.join((word for word, mark in phrase)), phrase[0][1]])
    

    【讨论】:

    • 这成功了!谢谢!我之前没有看到你用于第 5 行的方法实现过。很高兴知道。再次感谢。
    【解决方案2】:

    这是producer-consumer problem。有

    • 生产者:产生单个项目的section 序列
    • 消费者:将传入项目累积到一个块中并在准备好后返回该块的逻辑。
      • 由于该算法按原样逐个返回块,因此它很自然地适合作为生成器。

    由于生产者可以表示为单个循环语句,我们可以将消费者放入循环体中——但必须在第一次迭代之前对其进行初始化(因此,初始化代码将被复制)。

    棘手的部分是在迭代中以正确的顺序进行检查,这样我们就不必在代码的多个位置执行任何其他操作:

    • 首先检查我们是否也只是在累积或返回。
    • 如果返回,则返回块并重置它。
    • 然后,如果块不为空,则追加该项目,如果为空,则对其进行初始化
    • 最后,当序列结束时,如果有的话,返回最后一个待处理的块。

    None 比某些特定值更方便地表示块未初始化:1)通过真值测试快速检查; 2)我们不得不复制初始化代码,避免复制一些自定义值; 3) 不存在该项目的“神奇”初始值1

    def gen_captions(section):
        item = None
        for word, start, _ in section:
            if item:
                if start - item['time'] >= 2.5:
                    yield item
                    item = None
                else:
                    item['phrase']+=' '+word
            if not item:
                item = {'phrase':word,'time':start}            
        else:
            if item: yield item
    

    1某个值以这样的方式编制,它可以通过预期方式的检查,并会在第一次迭代时被“正常”值自动覆盖。
    在某些算法中,存在这样的值:例如选择最大数量时,初始结果可以设置为最低的数字。在这里,我们从不覆盖time,所以“自动覆盖”是不可能的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 2019-07-24
      • 1970-01-01
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多