【问题标题】:How to create a dictionary from a given matrix如何从给定的矩阵创建字典
【发布时间】:2018-12-11 01:05:48
【问题描述】:

假设我得到一个类似于电话键盘的矩阵-

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

我知道蛮力方法,但想知道一种有效地做到这一点的方法。

【问题讨论】:

  • 该矩阵是如何存储的?
  • 逻辑不清楚,能解释一下吗?
  • Matrix 将是一个列表列表,我编辑了这个问题。感谢您指出这一点。

标签: python algorithm dictionary matrix data-structures


【解决方案1】:

假设键盘存储为位置字典(元组 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)}

这个想法是为每个位置获取相邻点的值。

更新

要将列表 a 的列表转换为 键盘字典,您可以执行以下操作:

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}

方法的其余部分保持不变。

【讨论】:

    【解决方案2】:

    假设您的矩阵如下所示:

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

    【讨论】:

      【解决方案3】:

      您可以使用生成器函数:

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

      【讨论】:

      • 这是一个令人印象深刻的答案,我刚刚更新了问题并提到矩阵理想情况下是一个列表列表。您认为最有效的方法是什么?
      • 您能否添加 cmets 来解释您对 func(*_c)yield 语句所做的工作?另外,你的函数的时间复杂度是多少?此外,元组不需要排序,因此您可以删除它。
      • @kev * 是unpacking iterables 在函数调用或另一个相同类型容器中的特殊语法。 yield 被用作生成器表达式的一部分,该生成器表达式用于“延迟”生成值以降低内存使用率,从而提高性能。对于编辑后的解决方案,最坏情况的时间复杂度是O(n^2)
      【解决方案4】:
      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}
      

      丑陋但有效

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-14
        • 2020-09-21
        • 2022-11-02
        • 1970-01-01
        相关资源
        最近更新 更多