Python中的报错 TypeError: unhashable type

Hash知识笔记

  • 1.故事的起因
  • 2.TypeError: unhashable type
  • 3.原因
  • 4.总结

1.故事的起因

在leetcode刷题目的时候,遇到一个模拟机器人行走的问题(大家可以打开连接看看原题),题目内容如下图所示:
Python中的报错 TypeError: unhashable type_第1张图片这个题目就是一个模拟的题目,本来以为能够简单AC的,但是出现问题。
我的题解思路: 就是储出好四个方向,接着把障碍物的位置存储到HashMap中,这样只需要模拟移动机器人一步一步移动就行,下一步不是障碍物就走,是障碍物就结束当前的直线移动。
出现了问题: 思路上没什么问题,但是我先用Java实现一下上述过程,我在思考障碍物的坐标是一个二维数组的形式给出来的,那我将每一组坐标存储到HashMap中的时候,这是对数组地址进行的Hash,不是依据内容进行Hash的,所以这样不能够实现判断下一步的坐标点是不是障碍物(原本计划就是每次移动之前,把下一步得坐标点拿到HashMap中存储的障碍物点中判断一下存在否,不存在就移动,存在的话就不能走)
于是很好奇官方题解是如何解决这个问题的,便看了参考题解:

Java题解

//Java实现方式
class Solution {
    public int robotSim(int[] commands, int[][] obstacles) {
         int[][] dirs = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        int px = 0, py = 0, d = 1;
        Set<Integer> set = new HashSet<Integer>();
        for (int[] obstacle : obstacles) {
            set.add(obstacle[0] * 60001 + obstacle[1]);
        }
        int res = 0;
        for (int c : commands) {
            if (c < 0) {
                d += c == -1 ? 1 : -1;
                d %= 4;
                if (d < 0) {
                    d += 4;
                }
            } else {
                for (int i = 0; i < c; i++) {
                    if (set.contains((px + dirs[d][0]) * 60001 + py + dirs[d][1])) {
                        break;
                    }
                    px += dirs[d][0];
                    py += dirs[d][1];
                    res = Math.max(res, px * px + py * py);
                }
            }
        }
        return res;
    }
}

Python题解

# Python题解
class Solution:
    def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int:
        dirs = [[-1,0],[0,1],[1,0],[0,-1]]
        px, py, d = 0, 0, 1
        mp = set([tuple(i) for i in obstacles])
        res = 0
        for c in commands:
            if c < 0: # 调整机器人方向
                d += 1 if c== -1 else -1
                d %= 4
            else:
                for i in range(c):
                    # 这里可以直接比较列表内容是否相等
                    if tuple([px + dirs[d][0], py + dirs[d][1]]) in mp:
                        break;
                    px, py = px + dirs[d][0], py + dirs[d][1]
                    res = max(res, px * px + py * py)
        return res

我看了两个语言的实现方式,题目用的Set将障碍物的坐标存储,去了一次重(HashMap的key底层实现就是用Set,所以HashMap和Set都可以用来判断里面是否存在某一个元素),所以我开始题目就开始懵了,Java为啥不可以将数组传入Set,而为啥Python中就是直接把列表转化为元组,然后就可以作为Set了??

2.TypeError: unhashable type

对于上面的困惑,我做了一些测试,把Python代码中的列表不转化为元组试一试,结果出现了下面的报错,原来Python中也不能将列表Hash化,那这样也就是说上面的问题不是语言差异带来的,而是编程设计不允许这样子。Python中的报错 TypeError: unhashable type_第2张图片

3.原因

顺着上面线索,我进行了一方探索,得到了下面的重要信息 大家可以看看原文:
上面报错说list是unhashable,那么就会有可哈希(hashable)类型。那么,什么类型为可哈希? 引用 Python3 官方解释:一个对象的哈希值如果在其生命周期内绝不改变,就被称为 可哈希 (它需要具有hash() 方法),并可以同其他对象进行比较(它需要具有eq() 方法)。可哈希对象必须具有相同的哈希值比较结果才会相同。一个对象的哈希值在生命周期内不改变,就被成为可哈希。 可哈希性使得对象能够作为字典键或集合成员使用,因为这些数据结构要在内部使用哈希值。可变容器(例如列表或字典)都不可哈希,只有可哈希对象才能作为字典的键。

而且在Python中对于tuple元素的hash化是通过元素内容来实现的,也就说在之后的题解中,我们可以将不变内容tuple化之后存储到set中,然后就可以便利的判断其他行来元素在不在set中了

4.总结

今天遇见这个问题还是说明自己的基础不扎实,对于hash的原理过程了解的不够深刻,还需要多多加油,把基础知识打扎实了,这也会对未来的学习和工作很有帮助

你可能感兴趣的:(算法笔记,python,开发语言,hash)