Как создать словарь из заданной матрицы - PullRequest
0 голосов
/ 11 декабря 2018

Предположим, мне дана матрица, похожая на клавиатуру телефона, например:

1 2 3
4 5 6
7 8 9
  0

Как создать следующий словарь, не вводя его самостоятельно (кортежи не обязательно должны быть отсортированы) -

my_dict = {1: (1, 2, 4, 5), 2: (1, 2, 3, 4, 5, 6), 3: (2, 3, 5, 6),
           4: (1, 2, 4, 5, 7, 8), 5: (1, 2, 3, 4, 5, 6, 7, 8, 9),
           6: (2, 3, 5, 6, 8, 9), 7: (0, 4, 5, 7, 8),
           8: (0, 4, 5, 6, 7, 8, 9), 9: (0, 5, 6, 8, 9),
           0: (0, 7, 8, 9)}

Этот словарь в основном сообщает мне все соседние цифры данного числа.Например, соседние цифры 1 равны 1, 2, 4, 5.

Редактировать: В идеале матрица должна храниться в виде списка списков:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [None, 0, None]]

Я знаю, грубыйсиловой подход, но хотел знать, как сделать это эффективно.

Ответы [ 4 ]

0 голосов
/ 11 декабря 2018
T9 = [
    [1,2,3],
    [4,5,6],
    [7,8,9],
    [None,0,None]
]

result = {T9[i][j]:[T9[i+di][j+dj] for dj in range(-1,2) for di in range(-1,2) if 0<= i+di <=3 and 0 <= j+dj <=2 and T9[i+di][j+dj] is not None]  for j in range(3) for i in range(4) if T9[i][j] is not None}

некрасиво, но работает

0 голосов
/ 11 декабря 2018

Предполагая, что клавиатура хранится в виде словаря позиций (кортеж x, y) и соответствующего числа в качестве значения, вы можете сделать что-то вроде этого:

import itertools


def distance(p1, p2):
    return sum((x1 - x2) ** 2 for x1, x2 in zip(p1, p2))


def neighbors(positions, target):
    return [position for position in positions if distance(target, position) < 4]


def numbers(kpad, keys):
    return tuple(sorted(map(kpad.get, keys)))


values = list(range(1, 10)) + [0]
positions = list(itertools.product([0, 1, 2], repeat=2)) + [(3, 1)]

keypad = dict(zip(positions, values))

result = {value: numbers(keypad, neighbors(keypad, key)) for key, value in keypad.items()}
print(result)

Вывод

{0: (0, 7, 8, 9), 1: (1, 2, 4, 5), 2: (1, 2, 3, 4, 5, 6), 3: (2, 3, 5, 6), 4: (1, 2, 4, 5, 7, 8), 5: (1, 2, 3, 4, 5, 6, 7, 8, 9), 6: (2, 3, 5, 6, 8, 9), 7: (0, 4, 5, 7, 8), 8: (0, 4, 5, 6, 7, 8, 9), 9: (0, 5, 6, 8, 9)}

Идея состоит в том, чтобы для каждой позиции получить значения соседних точек.

ОБНОВЛЕНИЕ

Чтобы преобразовать список из списков в словарь клавиатуры вы можете сделать что-то вроде этого:

data = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [None, 0, None]]
keypad = {(i, j): value for i, sub in enumerate(data) for j, value in enumerate(sub) if value is not None}

Остальная часть подхода остается прежней.

0 голосов
/ 11 декабря 2018

Предполагая, что ваша матрица выглядит примерно так:

m = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [None, 0, None]
]

Вы можете грубо форсировать свое решение и просто перебирать матрицу и собирать соседние ячейки, используя defaultdict:

from collections import defaultdict
from pprint import pprint

m = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [None, 0, None]
]

rows = len(m)
cols = len(m[0])

# adjacent cells
adjacency = [(i, j) for i in (-1, 0, 1) for j in (-1, 0, 1) if not i == j == 0]

d = defaultdict(list)
for r in range(rows):
    for c in range(cols):
        cell = m[r][c]
        if cell is not None:
            d[cell].append(cell)
            for x, y in adjacency:
                if 0 <= r + x < rows and 0 <= c + y < cols:
                    adjacent = m[r + x][c + y]
                    if adjacent is not None:
                        d[cell].append(adjacent)

# print sorted adjacent cells
pprint({k: tuple(sorted(v)) for k, v in d.items()})

Какиедает словарь отсортированных соседних ячеек:

{0: (0, 7, 8, 9),
 1: (1, 2, 4, 5),
 2: (1, 2, 3, 4, 5, 6),
 3: (2, 3, 5, 6),
 4: (1, 2, 4, 5, 7, 8),
 5: (1, 2, 3, 4, 5, 6, 7, 8, 9),
 6: (2, 3, 5, 6, 8, 9),
 7: (0, 4, 5, 7, 8),
 8: (0, 4, 5, 6, 7, 8, 9),
 9: (0, 5, 6, 8, 9)}
0 голосов
/ 11 декабря 2018

Вы можете использовать функцию генератора:

import re
def all_adjacent(_c, _graph):
   _funcs = [lambda x,y:(x+1, y), lambda x,y:(x+1, y+1), lambda x,y:(x+1, y-1), lambda x,y:(x, y+1), lambda x,y:(x-1, y+1), lambda x,y:(x-1, y-1), lambda x,y:(x, y-1), lambda x,y:(x-1, y)]
   yield _graph[_c[0]][_c[1]]
   for func in _funcs:
     a, b = func(*_c)
     try:
       if a >= 0 and b >= 0:
         _val = _graph[a][b]
         if _val != '  ':
           yield _val
     except:
       pass


s = """
1 2 3
4 5 6
7 8 9
  0  
"""
new_data = [re.findall('\d+|\s{2,}', i) for i in filter(None, s.split('\n'))]
final_results = {c:list(all_adjacent((i, d), new_data)) for i, a in enumerate(new_data) for d, c in enumerate(a) if c != '  '}
_result = {int(a):tuple(sorted(map(int, b))) for a, b in final_results.items()}

Выход:

{1: (1, 2, 4, 5), 2: (1, 2, 3, 4, 5, 6), 3: (2, 3, 5, 6), 4: (1, 2, 4, 5, 7, 8), 5: (1, 2, 3, 4, 5, 6, 7, 8, 9), 6: (2, 3, 5, 6, 8, 9), 7: (0, 4, 5, 7, 8), 8: (0, 4, 5, 6, 7, 8, 9), 9: (0, 5, 6, 8, 9), 0: (0, 7, 8, 9)}

Редактировать: сохранение матрицы в виде списка списков:

import re
def all_adjacent(_c, _graph):
  _funcs = [lambda x,y:(x+1, y), lambda x,y:(x+1, y+1), lambda x,y:(x+1, y-1), lambda x,y:(x, y+1), lambda x,y:(x-1, y+1), lambda x,y:(x-1, y-1), lambda x,y:(x, y-1), lambda x,y:(x-1, y)]
  yield _graph[_c[0]][_c[1]]
  for func in _funcs:
    a, b = func(*_c)
    try:
      if a >= 0 and b >= 0:
        _val = _graph[a][b]
        if _val is not None:
          yield _val
    except:
      pass

new_data = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [None, 0, None]]
final_results = {c:(i, d) for i, a in enumerate(new_data) for d, c in enumerate(a) if c is not None}
_result = {int(a):tuple(map(int, all_adjacent(b, new_data))) for a, b in final_results.items()}

Выход:

{1: (1, 4, 5, 2), 2: (2, 5, 6, 4, 3, 1), 3: (3, 6, 5, 2), 4: (4, 7, 8, 5, 2, 1), 5: (5, 8, 9, 7, 6, 3, 1, 4, 2), 6: (6, 9, 8, 2, 5, 3), 7: (7, 0, 8, 5, 4), 8: (8, 0, 9, 6, 4, 7, 5), 9: (9, 0, 5, 8, 6), 0: (0, 9, 7, 8)}
...