【问题标题】:Combine list of dictionaries based on particular key value根据特定键值组合字典列表
【发布时间】:2018-08-20 16:23:12
【问题描述】:

我是 Python 新手,我正在尝试在脚本中解决这个问题。

我有 2 个字典列表,如下所示:

en_list = [{'time': 840, 'text': "I want to introduce you to some\nvery wise kids that I've known,"}, 
           {'time': 5480, 'text': 'but first I want\nto introduce you to a camel.'}, 
           {'time': 8720, 'text': 'This is Cassie, a therapy camel\nvisiting one of our young patients'}, 
           {'time': 13000, 'text': 'in her room,'},
           {'time': 14920, 'text': 'which is pretty magical.'}]

fr_list = [{'time': 840, 'text': "Je veux vous présenter certains enfants\ntrès sages que j'ai rencontrés,"},
           {'time': 5480, 'text': 'mais je veux commencer\npar vous présenter un chameau.'},
           {'time': 8720, 'text': 'Voici Cassie, un chameau thérapeutique qui\nrend visite à une de nos jeunes patients'},
           {'time': 14920, 'text': 'ce qui est plutôt magique.'}]

我想创建一个新列表,其中仅包含“时间”键的匹配值。

我想出了这个,但显然它没有考虑时间键,尽管如果两个列表具有相同数量的字典,它就可以正常工作。

for i, m in enumerate(zip(en_list, fr_list), start=1):
    print(i, m[0], "=", m[1])

这会打印出以下内容:

1 {'time': 840, 'text': "I want to introduce you to some\nvery wise kids that I've known,"} = {'time': 840, 'text': "Je veux vous présenter certains enfants\ntrès sages que j'ai rencontrés,"}
2 {'time': 5480, 'text': 'but first I want\nto introduce you to a camel.'} = {'time': 5480, 'text': 'mais je veux commencer\npar vous présenter un chameau.'}
3 {'time': 8720, 'text': 'This is Cassie, a therapy camel\nvisiting one of our young patients'} = {'time': 8720, 'text': 'Voici Cassie, un chameau thérapeutique qui\nrend visite à une de nos jeunes patients'}
4 {'time': 13000, 'text': 'in her room,'} = {'time': 14920, 'text': 'ce qui est plutôt magique.'}

如您所见,尽管英文列表具有相同时间的正确文本,但它错误地将带有'time': 13000 的英语映射到带有'time': 14920 的法语,但上面的代码忽略了它。

所需的输出应包括所有具有“时间”键匹配值的项目,并忽略不匹配的项目。我怎样才能做到这一点?

提前感谢您的支持!

【问题讨论】:

  • 您的代码根本没有检查time 的值;相反,您只匹配列表中的物理位置。您必须至少 try 匹配 time 值。如果遇到困难,请在线搜索具有相同键的 dict 条目中的解决方案。

标签: python list dictionary merge


【解决方案1】:

正如您所说,您的解决方案没有考虑时间值。要为此制定一个可行的解决方案,我们需要获取每个列表的时间值,找出它们有哪些共同点,然后根据共同的时间值过滤原始列表。

# Make set of time values for given list.
get_times = lambda l: {d['time'] for d in l}
# Intersection of sets
times_shared = get_times(en_list) & get_times(fr_list)

# Get dicts whose time value is shared.
get_shared = lambda l: [d for d in l if d['time'] in times_shared]

for i, m in enumerate(zip(get_shared(en_list), get_shared(fr_list)), start=1):
    print(i, m[0], '=', m[1])

或者您可以先将列表转换为字典(time: text 对),这样会更简单:

makedict = lambda l: {d['time']: d['text'] for d in l}
en_dict = makedict(en_list)
fr_dict = makedict(fr_list)

# Intersection
times_shared = set(en_dict) & set(fr_dict)

for i, time in enumerate(times_shared, start=1):
    print('%d %d %r = %r' % (i, time, en_dict[time], fr_dict[time]))

2020 年 6 月 1 日更新:我上面的代码有一些不好的做法,例如 named lambdasl as a variable name。我也忘了排序times_shared。我可能会像这样重写第二个解决方案:

en, fr = ({d['time']: d['text'] for d in lst} for lst in [en_list, fr_list])

# Intersection
times_shared = sorted(set(en) & set(fr))

for i, time in enumerate(times_shared, start=1):
    print('%d %d %r = %r' % (i, time, en[time], fr[time]))

【讨论】:

  • 感谢您对 wjandrea 的支持。这工作得很好,它完美地得到了所有想要的结果。非常感谢你的支持。显然,我需要了解 lambda。它似乎非常有用。
  • @MZEID 欢迎您!我在这里使用 lamdbas 而不是单行函数,仅此而已。 Lambda 对匿名函数更有用,例如按值对 dict 进行排序:sorted(dict.items(), key=lambda t: t[1])
  • @MZe 仅供参考,事实证明命名 lambda 是不好的做法。查看我更新的解决方案。
  • 感谢一百万更新答案并让我了解它。对此,我真的非常感激。谢谢!
【解决方案2】:

从每个字典中创建一个列表,包括所有 time 值。找出两个列表共有的时间(制作另一个列表)。遍历这个常见时间列表,从两个列表中打印相应的字典。

这些步骤中的每一个都是教程和其他 Stack Overflow 问题中介绍的常见编程技术。编码留给学生作为练习。

【讨论】:

    【解决方案3】:
    list(filter(lambda item: item[0].get('time') == item[1].get('time'), zip(en_list, fr_list)))
    

    (已编辑):也许这会起作用

    result = []
    for k, en in enumerate(en_list):
        for fr in fr_list:
            if en.get('time') == fr.get('time'):
                result.append({k: '{} = {}'.format(en, fr)})
    

    【讨论】:

    • 这只有在相同的时间在列表中的相同位置时才有效,但事实并非如此。时间 14920 从输出中排除。
    • 非常感谢 Higor 对此的帮助。这对于上面的示例非常有效,但似乎一旦遇到不匹配的键值就会停止循环。如果 2 个列表具有相同数量的字典,它将完美地获取它们,但如果存在不匹配,则停止循环。有没有办法让它继续循环并忽略不匹配的值?再次感谢您的支持。
    • 再次感谢 Higor 抽出宝贵时间提供支持。您的解决方案的逻辑工作得很好,并且得到了正确的结果,但由于某种原因,打印出来的字符串充满了反斜杠。不知道为什么,但感谢一百万的支持。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 2016-02-22
    • 1970-01-01
    相关资源
    最近更新 更多