【问题标题】:Create a 3 level dictionary from a list of strings with multiple uniqe values for each key从每个键具有多个唯一值的字符串列表创建一个 3 级字典
【发布时间】:2019-02-27 07:43:21
【问题描述】:

我有一个文本字符串列表,我需要从中构建一棵树,据我了解,实现这一目标的正确数据结构是字典。 每个字符串的大小是固定的,所有元素的格式都是相同的,因此不需要额外的检查。 列表的每条记录都是格式为 DD/MM/YYYY 的日期,并且年/年应该在树的根部(键,这里没有重复),每年可能是多个月(内没有重复的月份同一年)作为值,每个月多天(同一个月内没有重复的天数)。

字符串列表示例:

数据 = ['04/02/2018', '05/02/2018', '06/02/2018', '01/03/2018', “2018 年 10 月 3 日”、“2017 年 8 月 9 日”、“2017 年 9 月 9 日”、“2017 年 11 月 10 日”、 '11/12/2017'、'14/06/2018'、'15/06/2018'、'24/07/2018'、'26/07/2018'、'30/08/2018'、'31 /08/2018', '01/09/2018']

除了解决方案,如果有的话,我还想解释一下以便理解。

这是我到目前为止写的,这显然是错误的,因为结果是一个只有最后 2 项的字典。

d = {}
for item in data:
    rec = item.split('/')
    d.update({rec[2]:{rec[1]:(rec[0])}})

该数据所需的输出如下所示:

{'2017': {'09': ['08', '09'], '10': ['11'], '12': ['11']},
 '2018': {'02': ['04', '05', '06'],
          '03': ['01', '10'],
          '06': ['14', '15'],
          '07': ['24', '26'],
          '08': ['30', '31'],
          '09': ['01']}}

【问题讨论】:

  • 请添加您的代码,您在哪里遇到问题?
  • 到目前为止我没有任何工作代码,但我可以发布我可耻的尝试。
  • 好,就是这样,一切顺利。
  • 是的,最终的结果应该是这样的,抱歉我忘记发了。
  • “我需要构建一棵树,据我了解,实现它的正确数据结构是字典。”不必要。树通常使用您自己的自定义数据结构来实现(也可能由 dict 对象组成,但可能涉及其他对象)

标签: python python-3.x dictionary ordereddictionary


【解决方案1】:

你不需要一棵树。您可以使用 dicts 的 dict,将列表作为最里面的值。

您可以使用defaultdict 作为主要结构

result = defaultdict(defaultdict(list))

for date in data:
    day, month, year = date.split('/')
    result[year][month].append(day)

defaultdict 的作用是

  • 对于内部字典:您可以直接append。如果没有列表,则会创建一个新的空列表。
  • 对于外部字典:类似地,您可以参考键 month 假设已经有一个字典作为其值。如果没有,则创建一个新的。

【讨论】:

  • 值应该是“天”
  • @blue_note 你运行过这个吗?因为我很确定您不能在 for 语句中拆分列表对象
  • @vash_the_stampede:当然,错误。谢谢,已编辑。
  • 没有问题,我在运行嵌套的 defaultdict 时也遇到了错误,它不允许内部 defaultdict 是可迭代的,也许我错过了一些东西
【解决方案2】:

有多种方法可以实现这一点。您可以使用来自collections 模块的defaultdict。但也可以使用普通的dict.setdefault 方法来完成。

setdefault(key[, default])

如果 key 在字典中,则返回其值。如果不是,则插入 key,其值为 default 并返回 default默认默认为

我们循环遍历数据,将其拆分为日、月和年字符串。然后我们在基础树中查找年份键,如果它不存在,我们为它创建一个新的空字典。然后我们在那个年份字典中查找月份键,如果它不存在则为其创建一个新列表。最后,我们将日期字符串附加到月份列表中。

from pprint import pprint

data = [
    '04/02/2018', '05/02/2018', '06/02/2018', '01/03/2018', '10/03/2018', '08/09/2017', '09/09/2017',
    '11/10/2017', '11/12/2017', '14/06/2018', '15/06/2018', '24/07/2018', '26/07/2018', '30/08/2018',
    '31/08/2018', '01/09/2018'
]

tree = {}

for s in data:
    day, mon, year = s.split('/')
    ydict = tree.setdefault(year, {})
    mlist = ydict.setdefault(mon, [])
    mlist.append(day)

pprint(tree)

输出

{'2017': {'09': ['08', '09'], '10': ['11'], '12': ['11']},
 '2018': {'02': ['04', '05', '06'],
          '03': ['01', '10'],
          '06': ['14', '15'],
          '07': ['24', '26'],
          '08': ['30', '31'],
          '09': ['01']}}

我们可以将主循环的 3 个步骤合并为一行,但是阅读起来有点困难:

for s in data:
    day, mon, year = s.split('/')
    tree.setdefault(year, {}).setdefault(mon, []).append(day)

【讨论】:

  • 这很好用,易于阅读和理解。我知道python one 班轮是首选,但对于我的python 水平来说,更长的方式简直是完美的。谢谢。
  • 我想让你看看这个,我正在解决它我正在考虑使用 .split(':') 并设置一个字典,其中每个键的唯一性都在 : 之前然后从那里开始,检查一下,我想你会很适合这个stackoverflow.com/questions/52460092/…
  • 在附加之前检查值“day”是否在 mlist 中,实际上给出了最终的期望结果。如果天不在 mlist 中:mlist.append(day)
  • @bit-by-bit 啊。我没有意识到您需要排除重复的日子。我以为你是说数据中永远不会有重复的日子。您的解决方案很好,但另一种选择是将日期存储在集合中而不是列表中,这将自动消除重复项,就像 dict 键消除重复年份和月份一样。为此,您将使用set.add 方法,它等效于list.append。 OTOH,集合是无序集合,可能不适合您的用例。
  • @PM2Ring 实际订购是最终目的的首选。关于 pprint 的另一个问题,为什么只有一个字典以树形样式打印,而其他字典不是?我在一些更大的真实数据列表上尝试了代码,我看到只有一个“分支”以树状扩展,其余的则不是。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
相关资源
最近更新 更多