【问题标题】:Populate a dictionary with multiple comprehensions用多种理解填充字典
【发布时间】:2018-11-26 09:56:14
【问题描述】:

我正在尝试创建一个看起来像这样的字典(部分示例):

{(1, 1): 'Residential', (2, 1): 'Residential', (3, 1): 'Residential', (1, 2): 'Crafts', (2, 2): 'Crafts', (3, 2): 'Crafts', (4, 1): 'Law, Government', (5, 1): 'Law, Government', (4, 2): 'Public Space', (5, 2): 'Public Space', (6, 1): 'Vice', (6, 2): 'Entertainment'}

对于一些更聪明的解决方案来说,关键逻辑似乎是一个问题,即一组值分布在 3 个键上,另一组值分布在 2 个键上,第三组各有一个键。

我宁愿通过某种理解以编程方式创建它,而不是多次编写重复项。

USE = dict([(n, 1), "Residential"] for n in range(1, 4))

这很有效,例如,创建它的第一部分。我可以这样做:

USE2 = dict([(n, 2), "Crafts"] for n in range(1, 4))
USE.update(USE2)

这对于常量来说是凌乱、不优雅和糟糕的风格。

我对任何其他策略都束手无策。

我尝试了一些形式的串行理解:

USE = dict([(n, 1), "Residential"] for n in range(1, 4),
           [(n, 2), "Crafts"] for n in range(1, 4),...

但这失败了,因为 dict() 不接受多个参数。

我做不到Python 3 unpacking generalizations

USE = dict(**dict([(n, 1), "Residential"] for n in range(1, 4)),
           **dict([(n, 2), "Crafts"] for n in range(1, 4)),...

因为我不明白的原因,这种风格仅限于字符串。使用字符串需要稍后转换将用于引用 dict 的随机数,这似乎更让人头疼(尽管我想这取决于是否有一个优雅的解决方案)。

dict comprehension 似乎不够健壮(此处的完整数据:前 6 个是后 6 个的 3 倍):

space = ["Residential", "Crafts", "Labor", "Shops", "Trade", "Hospitality",
     "Law, Government", "Public Space", "Power", "Manufacture", "Transportation", "Leisure",
     "Vice", "Entertainment", "Storage", "Cultivation", "Academic", "Artists"]
TRY = {(y, x+1): s for x, s in enumerate(space) for y in range(1, 7)}

由于列表大小,这最终离开了我的 6x6 边界。如果我对 x 取模,它最终会覆盖条目。似乎我必须编写一个专门的函数来覆盖古怪的 3/2/1 重复,这对于通过某种理解应该是可能的似乎是不必要的。

有没有办法在一行中声明具有这种复杂性的字典?如果不是,那么声明这种常量的正确样式是什么?

【问题讨论】:

  • TRY 有什么问题?这不是您期望的输出吗?
  • 字典真的是正确的数据结构吗?您是否考虑过使用 2D 参差不齐的列表?
  • @Austin 在上面的例子中,TRY 结束于:{(1, 1): 'Residential', (2, 1): 'Residential', (3, 1): 'Residential', (4, 1): 'Residential', (5, 1): 'Residential', (6, 1): 'Residential',... (1, 18): 'Artists', (2, 18): 'Artists', (3, 18): 'Artists', (4, 18): 'Artists', (5, 18): 'Artists', (6, 18): 'Artists'} 我想要的范围是 (1,1) 到 (6,6),18 是正确的。此外,我想将“住宅”限制为 (1,1)...(3,1),这会将所有内容循环 6 次迭代。
  • @Code-Apprentice 我不熟悉 2D 参差不齐的列表。我可以去看看。
  • @Zim 当每一行都有相同数量的元素时,通常使用二维列表。如果不是这种情况,则 2D 列表称为“不规则”。出于您的目的,这可能不是一个重要的细节,但可以为您提供一个可能相关的搜索词。

标签: python dictionary python-3.6 dictionary-comprehension


【解决方案1】:

俗话说:

不要写程序,写程序会写程序。

我的建议是启动一个交互式会话(或 IPython),创建部分字典并使用 update 合并它们。

然后打印出组合的dict 并将其粘贴到您的源代码中。

【讨论】:

  • 我认为我驳回它的主要原因是由于可维护性——如果我真的考虑一下,这甚至不是一个真正的问题。即使是这样,如果我想要进行简单的查找/替换无法满足的更改,我可以将构建过程包含在 cmets 中。
【解决方案2】:

您描述的二维结构实际上非常适合 numpy 数组:

>>> import numpy as np
>>> 
>>> space = ["Residential", "Crafts", "Labor", "Shops", "Trade", "Hospitality",
...      "Law, Government", "Public Space", "Power", "Manufacture", "Transportation", "Leisure",
...      "Vice", "Entertainment", "Storage", "Cultivation", "Academic", "Artists"]
>>> 
>>> sparr = np.array(space, dtype=object).reshape(3,6).repeat((3,2,1), axis=0)

请注意这一行的读法多么自然:创建一个数组,重新整形为 3 行,每列 6 列,垂直(0 轴)第一个元素重复 3 次,第二个元素重复两次,最后一个元素重复一次。

结果:

>>> sparr
array([['Residential', 'Crafts', 'Labor', 'Shops', 'Trade', 'Hospitality'],
       ['Residential', 'Crafts', 'Labor', 'Shops', 'Trade', 'Hospitality'],
       ['Residential', 'Crafts', 'Labor', 'Shops', 'Trade', 'Hospitality'],
       ['Law, Government', 'Public Space', 'Power', 'Manufacture', 'Transportation', 'Leisure'],
       ['Law, Government', 'Public Space', 'Power', 'Manufacture', 'Transportation', 'Leisure'],
       ['Vice', 'Entertainment', 'Storage', 'Cultivation', 'Academic', 'Artists']], dtype=object)

这几乎是正确的,只是索引是从零开始的,所以我们需要添加一个虚拟列和一个虚拟行:

result = np.full((7, 7), None, dtype=object)
>>> result[1:, 1:] = sparr
>>> 
>>> result
array([[None, None, None, None, None, None, None],
       [None, 'Residential', 'Crafts', 'Labor', 'Shops', 'Trade', 'Hospitality'],
       [None, 'Residential', 'Crafts', 'Labor', 'Shops', 'Trade', 'Hospitality'],
       [None, 'Residential', 'Crafts', 'Labor', 'Shops', 'Trade', 'Hospitality'],
       [None, 'Law, Government', 'Public Space', 'Power', 'Manufacture', 'Transportation', 'Leisure'],
       [None, 'Law, Government', 'Public Space', 'Power', 'Manufacture', 'Transportation', 'Leisure'],
       [None, 'Vice', 'Entertainment', 'Storage', 'Cultivation', 'Academic', 'Artists']], dtype=object)

现在,这是“鸭子” - 相当于你的字典,查找方式。例如:

>>> result[2,1]  # result[(2,1)] also works
'Residential'

【讨论】:

  • 我一定会玩这个,因为我更喜欢 numpy 的力量,甚至比我害怕它。
【解决方案3】:

如果您正在寻找单行理解,那么这样的事情怎么样?

a = (3,'Residential',3,'Crafts',2,'Law, Government',2,'Public Space',1,'Vice',1,'Entertainment')
use = dict()
use.update(dict([(n / 2 + 1, s), a[n+1]] for s in range(1, 4) for n in range(0, len(a), 2) ))

【讨论】:

    【解决方案4】:

    该密钥方案有点神秘。这是一种稍微压缩它的方法。让 (n0, n1) 成为给定类别名称的键。对于每个名称,n1 是常量,但 n0 覆盖一个连续的范围,因此我们可以只存储该范围的第一项和最后一项。然后我们使用带有双 for 循环的 dict 理解将压缩版本扩展为您真正想要的 dict。

    # Condensed key table.
    # Each name in the full table has a 2-tuple key (n0, n1)
    # The tuples in `table` are (first_n0, last_n0, n1)
    table = {
        'Residential': (1, 3, 1),
        'Crafts': (1, 3, 2),
        'Law, Government': (4, 5, 1),
        'Public Space': (4, 5, 2),
        'Vice': (6, 6, 1),
        'Entertainment': (6, 6, 2),
    }
    
    out = {(n0, n1): name for name, (first, last, n1) in table.items()
        for n0 in range(first, last + 1)
    }
    
    for k, v in out.items():
        print(f'{k}: {v!r},')
    

    出局

    (1, 1): 'Residential',
    (2, 1): 'Residential',
    (3, 1): 'Residential',
    (1, 2): 'Crafts',
    (2, 2): 'Crafts',
    (3, 2): 'Crafts',
    (4, 1): 'Law, Government',
    (5, 1): 'Law, Government',
    (4, 2): 'Public Space',
    (5, 2): 'Public Space',
    (6, 1): 'Vice',
    (6, 2): 'Entertainment',
    

    这是使用传统 for 循环的 dict comp 的等价物。您可能会发现此版本更具可读性。

    out = {}
    for name, (first, last, n1) in table.items():
        for n0 in range(first, last + 1):
            out[n0, n1] = name
    

    【讨论】:

    • 是的!这是来自an RPG 的表格,使用 d6 滚动 - 此表格使用 y 轴的一系列结果(1-3、4-5、6)。
    • @Zim 如果范围总是 (1-3, 4-5, 6),那么我的压缩表可以简化,因为它不需要存储 last_n0。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-25
    • 1970-01-01
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多