Я пытаюсь создать словарь, который выглядит примерно так (частичный пример):
{(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 клавишам, другой набор распространяется по двум клавишам, а третий набор имеет по одному ключу.
Вместо того, чтобы писать дубликаты несколько раз, я предпочел бы создать его программным путем с каким-то пониманием.
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:
USE = dict(**dict([(n, 1), "Residential"] for n in range(1, 4)),
**dict([(n, 2), "Crafts"] for n in range(1, 4)),...
Потому что этот стиль ограничен строками по причинам, которые я не понимаю. Использование строк потребует более позднего преобразования случайных чисел, которые будут использоваться для ссылки на dict, и похоже на боль в головной боли (хотя, я полагаю, это зависит от того, есть ли там элегантное решение вообще).
И понимание dict не кажется достаточно прочным (полные данные здесь: где первые 6 в 3 раза чаще, чем последние 6):
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, которое кажется ненужным для того, что должно быть возможно через какое-то понимание.
Есть ли способ объявить словарь с такой сложностью в одной строке? Если нет, то какой стиль нужно декларировать такой постоянной?
Как говорится:
Не пишите программы, пишите программы, которые пишут программы.
Я бы предложил начать интерактивный сеанс (или IPython), создать частичные dicts и использовать update
для их объединения.
Затем распечатайте объединенный dict
и вставьте его в исходный код.
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 строки, по шесть столбцов, повторите по вертикали (ось 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)
Теперь это "утка" -equivalent для вашего словаря, ориентированного на поиск. Например:
>>> result[2,1] # result[(2,1)] also works
'Residential'
Если вы ищете однострочное понимание, как насчет чего-то подобного?
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) ))
Эта ключевая схема немного загадочна. Здесь один способ немного конденсировать его. Пусть (n0, n1) является ключом для данного названия категории. Для каждого имени n1 является константой, но n0 охватывает смежный диапазон, поэтому мы можем просто сохранить первый и последний элементы этого диапазона. Затем мы используем Dict понимание с двойным 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',
Здесь эквивалент этого dict comp, использующий традиционные for
циклов. Вы можете найти эту версию немного более читаемой.
out = {}
for name, (first, last, n1) in table.items():
for n0 in range(first, last + 1):
out[n0, n1] = name