填充具有多种理解的字典

时间:2018-06-17 07:05:33

标签: python dictionary python-3.6 dictionary-comprehension

我试图创建一个类似于此的字典(部分示例):

{(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 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重复,这对于通过某种理解应该是可能的是不必要的。

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

4 个答案:

答案 0 :(得分:1)

俗话说:

  

不要编写程序,编写编写程序的程序。

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

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

答案 1 :(得分:1)

您描述的2D结构实际上非常适合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)

现在,这是" duck" - 等同于你的字典,查找方式。例如:

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

答案 2 :(得分:0)

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

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) ))

答案 3 :(得分:0)

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

# 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