【问题标题】:Looping through multiple dictionaries to create new dictionary from values in python循环遍历多个字典以从 python 中的值创建新字典
【发布时间】:2019-12-11 20:48:25
【问题描述】:

我有两个字典列表。两者都包含一项数据以及一个开始和停止时间戳。第一个列表包含表示对具有开始和停止时间的文本序列的观察的字典。它看起来像这样:

list_1 = [
      {'word': 'hey hows it going?', 's1': 1.2, 's2': 3.6},
      {'word': 'um', 's1': 3.7, 's2': 4.2},
      {'word': 'its raining outside today', 's1': 4.3, 's2': 5.0},
      {'word': 'and its really cold', 's1': 5.1, 's2': 6.6},
      {'word': 'dont you think?', 's1': 6.7, 's2': 8.1},
      {'word': 'its awful', 's1': 7.7, 's2': 9.0}
    ]

第二个列表包含表示对具有开始和停止时间的类别的观察的字典。它看起来像这样:

list_2 = [
  {'category': 0, 's1': 0.0, 's2': 3.8},
  {'category': 1, 's1': 3.9, 's2': 4.9},
  {'category': 1, 's1': 5.0, 's2': 7.2},
  {'category': 0, 's1': 7.3, 's2': 7.6},
  {'category': 1, 's1': 7.7, 's2': 9.0}
]

我想根据以下逻辑使用list_1['word'] 值在list_2 的字典中创建一个新项目:

  • 如果来自list_1['s1'] 的值大于来自list_2['s1'] 的值且小于来自list_2['s2'] 的值,则将来自list_1['word'] 的所有值附加到新项目list_2['word'] 中。

  • 如果来自list_1['s1'] 的值大于来自list_2['s1'] 的值且小于来自list_2['s2'] 的值,但list_1['s2'] 大于来自list_2['s1'] 的值,则追加来自list_1['word'] 进入新项目,list_2['word'] 用于 NEXT 字典。

另一种思考方式是在循环 list_1 和 list_2 时:

  • 如果来自 list_1 项目的时间戳在 list_2 项目的时间戳内,则将 list_1 单词添加到 list_2 中的新键值对中。

  • 如果来自list_1 项目的时间戳不属于list_2 项目的时间戳,例如list_2[0] 中的单词“开始”但list_2[1] 中的“结束”,然后添加@987654345 @ 从list_1[0]list_2[1]

应该是这样的:

expected_output =[
   {'category': 0,
      's1': 0.0,
      's2': 3.8,
      'words': 'hey hows it going? um'},
   {'category': 1,
      's1': 3.9,
      's2': 4.9,
      'words': 'its raining outside today'},
   {'category': 1,
      's1': 5.0,
     's2': 7.2,
     'words': 'and its really cold'},
   {'category': 0,
      's1': 7.3,
      's2': 9.0,
      'words': 'dont you think? its awful'}
  ]

【问题讨论】:

  • 您的两个“列表”只有 1 个元素,它是一个字典,其顺序整数键从 0 开始(因此它们的索引与列表非常相似)是有意的吗?您概述了非常清晰的逻辑,我假设您的代码无法按您想要的方式工作?你能分享你到目前为止的情况并解释哪里出了问题吗?
  • 感谢您的反馈。我看到每个都是一个 1 元素列表。为简单起见,如果您更有效率,我可以通过删除顺序整数键来转换为字典列表。在代码方面,我不确定从哪里开始。

标签: python list dictionary


【解决方案1】:

您的原始算法是“下一个”算法,您确定这是您想要的吗?我试图实现你所说的,但不清楚当一个短语重叠超过 2 个发言者时会发生什么。

一些设计说明:

  • 如果边界是 [a, b) 而不是 [a, b],您的数据会更有意义 - 3.65 应该去哪里?
  • 将值存储为列表(或根据开始时间确定注入顺序)可能更可重用,而不是在此处将它们展平为带有空格的字符串。之后您可以随时将它们展平
START, END = 's1', 's2'

def require_speaker(start, end):
    ''' Return the latest speaker in start <= time <= end '''
    # This should be an interval tree if your data is large
    # https://en.wikipedia.org/wiki/Interval_tree

    # Exactly one of the first 3 is true, so we could use an `else`,
    # listing all for clarity.
    after = lambda v: v[END] < start
    overlaps = lambda v: start <= v[END] and v[START] <= end
    before = lambda v: end < v[START]
    contained = lambda v: v[START] <= start and end <= v[END]

    take_next = False
    for speaker in list_2:
        if take_next:
            return speaker
        if after(speaker):
            continue
        elif contained(speaker):
            return speaker
        elif overlaps(speaker):
            take_next = True
        elif after(speaker):
            break  # Missed it somehow (can't happen if full coverage)
    raise LookupError('no speaker in range %s - %s' % (start, end))

# Prepare a list for phrases
for speakers in list_2:
    speakers['words'] = []
# Populate phrases for each speaker
for phrase in list_1:
    speaker = require_speaker(phrase[START], phrase[END])
    speaker['words'].append(phrase['word'])
# Convert back to string
for speakers in list_2:
    speakers['words'] = ' '.join(speakers['words'])

使用您的数据

list_1 = [
      {'word': 'hey hows it going?', 's1': 1.2, 's2': 3.6},
      {'word': 'um', 's1': 3.7, 's2': 4.2},
      {'word': 'its raining outside today', 's1': 4.3, 's2': 5.0},
      {'word': 'and its really cold', 's1': 5.1, 's2': 6.6},
      {'word': 'dont you think?', 's1': 6.7, 's2': 8.1},
      {'word': 'its awful', 's1': 7.7, 's2': 9.0}
    ]

list_2 = [
  {'category': 0, 's1': 0.0, 's2': 3.8},
  {'category': 1, 's1': 3.9, 's2': 4.9},
  {'category': 1, 's1': 5.0, 's2': 7.2},
  {'category': 0, 's1': 7.3, 's2': 7.6},
  {'category': 1, 's1': 7.7, 's2': 9.0}
]

你得到

>>> import pprint
>>> pprint.pprint(list_2)
[{'category': 0, 's1': 0.0, 's2': 3.8, 'words': 'hey hows it going?'},
 {'category': 1, 's1': 3.9, 's2': 4.9, 'words': 'um'},
 {'category': 1,
  's1': 5.0,
  's2': 7.2,
  'words': 'its raining outside today and its really cold'},
 {'category': 0, 's1': 7.3, 's2': 7.6, 'words': 'dont you think?'},
 {'category': 1, 's1': 7.7, 's2': 9.0, 'words': 'its awful'}]

请注意,您的预期输出与您的算法不匹配:

  • “um”(3.7-4.2)应放在3.9-4.9范围内
  • “今天外面下雨”(4.3-5.0)应该放在5.0-7.2范围内
  • “dont you think”(6.7-8.1)应该放在7.7-9.0范围内

【讨论】:

    最近更新 更多