持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
前言
Map对象是ES6中引入的JavaScript语法,Map对象的在存储中从健的类别的多类型和性能等方面都要比Object对象要优雅。下面我们会介绍一下Map对象,然后通过哈希相关算法题来加强巩固知识。
Map 对象介绍
Map 对象和Object的区别
平时写代码的时候,如果要用JavaScript表示哈希对象或者说哈希表,我们这样子,
let hashTable = {} // 创建hashTable哈希对象,
哈哈,这不是就是普通的JavaScript对象吗? 是的。Object
和 Map
类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成 Map
使用。
不过 Map
和 Object
有一些重要的区别,在下列情况中使用 Map
会是更好的选择:
场景 | Map | Object |
---|---|---|
意外的键 | Map 默认情况不包含任何键。只包含显式插入的键。 | 一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。 |
键的类型 | 一个 Map 的键可以是任意值,包括函数、对象或任意基本类型。 | 一个 Object 的键必须是一个 String 或是 Symbol 。 |
键的顺序 | Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 | 虽然 Object 的键目前是有序的,但并不总是这样,而且这个顺序是复杂的。因此,最好不要依赖属性的顺序。 |
Size | Map 的键值对个数可以轻易地通过 size 属性获取。 | Object 的键值对个数只能手动计算 |
迭代 | Map 是 可迭代的 的,所以可以直接被迭代。 | 对象可以实现迭代协议,或者你可以使用 Object.keys 或 Object.entries 。 |
性能 | 在频繁增删键值对的场景下表现更好。 | 在频繁添加和删除键值对的场景下未作出优化。 |
备注: 虽然从 ES5 开始可以用
Object.create(null)
来创建一个没有原型的对象,但是这种用法不太常见。
自 ECMAScript 2015 规范以来,对象的属性被定义为是有序的;ECMAScript 2020 则额外定义了继承属性的顺序。参见 OrdinaryOwnPropertyKeys 和 EnumerateObjectProperties 抽象规范说明。但是,请注意没有可以迭代对象所有属性的机制,每一种机制只包含了属性的不同子集。(
for-in
仅包含了以字符串为键的属性;Object.keys
仅包含了对象自身的、可枚举的、以字符串为键的属性;Object.getOwnPropertyNames
包含了所有以字符串为键的属性,即使是不可枚举的;Object.getOwnPropertySymbols
与前者类似,但其包含的是以Symbol
为键的属性,等等。)
Map的实例属性和方法
size 属性
-
返回
Map
对象中的键值对数量。
size和数组的length属性有点像,也是返回类似总个数,
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map.size); // 2
使用时注意,size是属性,不要这样加括号size()
clear 方法
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
map.clear()
console.log(map.size); //0
- 移除
Map
对象中所有的键值对。
delete方法
-
移除
Map
对象中指定的键值对,如果键值对存在,返回true
,否则返回false
。调用delete
后再调用Map.prototype.has(key)
将返回false
。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map); // Map(2) { 'tom' => 18, 'jack' => 28 }
map.delete('tom')
console.log(map); // Map(1) { 'jack' => 28 }
get方法
-
返回与
key
关联的值,若不存在关联的值,则返回undefined
。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map.get('tom')); // 18
has 方法
-
返回一个布尔值,用来表明
Map
对象中是否存在与key
关联的值。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map.has('tom')); // true
set方法
-
在
Map
对象中设置与指定的键key
关联的值value
,并返回Map
对象。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map); // Map(2) { 'tom' => 18, 'jack' => 28 }
keys 迭代方法
-
返回一个新的迭代对象,其中包含
Map
对象中所有的键,并以插入Map
对象的顺序排列。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map.keys()); // [Map Iterator] { 'tom', 'jack' }
values 迭代方法
-
返回一个新的迭代对象,其中包含
Map
对象中所有的值,并以插入Map
对象的顺序排列。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map.values()); // [Map Iterator] { 18, 28 }
entries 迭代方法
-
返回一个新的迭代对象,其为一个包含
Map
对象中所有键值对的[key, value]
数组,并以插入Map
对象的顺序排列。
let map = new Map();
map.set('tom', 18)
map.set('jack', 28)
console.log(map.entries()); // [Map Entries] { [ 'tom', 18 ], [ 'jack', 28 ] } 得到二维数组
算法题实战
以下四道题目来自牛客网,到时大厂常见算法题,使用的解答方式也都是巧妙的运用了哈希对象,存值取值的特点。下面一起来感受体会以下吧
两数之和
题目描述
解析参考
- 创建哈希对象
- 遍历数组找到每一轮与
number[i]
相加等于target
的值为num - 如果存在map中就返回num的下标值和当前下标i+1,因为下标从1开始所以要加一
- 将当前number[i]值和下标保存到map中
function twoSum( numbers , target ) {
let map = new Map() // 创建哈希对象
for(let i = 0; i<numbers.length;i++ ){
let num = target - numbers[i] // 每一轮与number[i]相加等于target的值
if(map.has(num)) return [map.get(num),i+1] // 如果存在map中就返回num的下标值和当前下标i+1,因为下标从1开始所以要加一
else map.set(numbers[i], i+1) // 将当前number[i]值和下标保存到map中
}
}
这题使用map对象的特性,帮我们存储了每个值和它的下标,然后我们通过判断满足num+number[i]=target
的num是否在之前出现过,出现过就返回对应下标,不满足就继续遍历,因为下标要升序返回所以写[map.get(num),i+1]
数组中出现次数超过一半的数字
题目描述
解析参考
- 创建哈希对象
- 遍历数组判断对应数组的每一项是否在哈希对象中,map记录它们出现的次数
- 返回出现次数超过一半的数组项
function MoreThanHalfNum_Solution(numbers)
{
let len = numbers.length // 数组长度
let half = len >> 1 // 数组长度的一半,位运算相当于 len/2
let map = new Map() // 创建哈希对象
for(let item of numbers){
if(map.has(item)) map.set(item, map.get(item)+1) // 如果值在map中了,则将记录结果加一
else map.set(item,1) // 如果不在map中,则记录其结果为1
if(map.get(item) > half) return item // 如果i出现次数超过half就返回
}
}
数组中只出现一次的两个数字
题目描述
解析参考
- 创建map对象和res数组报错结果
- 遍历数组用map记录数组每项出现的次方
- 遍历map 对象,找出出现次数为一次的两个数字
- 注意map.forEach((value,key)) 中value和key顺序不可以变,第一个参数表示value,第二个参数表示key。
/**
* @param array int整型一维数组
* @return int整型一维数组
*/
function FindNumsAppearOnce( array ) {
// write code here
let len = array.length
let map = new Map()
let res = [] // 存储结果
// 遍历数组用map记录数组每项出现的次方
for(let i = 0; i <len; i++){
if(map.has(array[i])){
map.set(array[i],map.get(array[i])+1)
}
else map.set(array[i], 1)
}
// 遍历map 对象,找出出现次数为一次的两个数字
// 注意map.forEach((value,key)) 中value和key顺序不可以变,第一个参数表示value,第二个参数表示key,
map.forEach((value,key) => {
if(value ==1) res.push(key)
})
// 返回升序返回结果
return res.sort((a,b) => a-b)
}
缺失的第一个正整数
题目描述
解析参考
- 创建map对象,遍历数组,将数组的值记录到map对象中
- while循环找到最小正整数。
/**
* @param nums int整型一维数组
* @return int整型
*/
function minNumberDisappeared( nums ) {
let map = new Map() // 创建map对象
let n = nums.length // 数组长度
// 遍历nums数组,将出现过的数记录在map对象中
for(let i = 0; i<n; i++){
if(!map.has(nums[i])) map.set(nums[i], 1)
}
let res = 1 // 最小正整数为1
// 从1 往上加,没有连续的值就是最小正整数了,如果都是连续 的值,那结果就是map对象中的最大数加一了
while(map.has(res)){
res++
}
return res
}
总结
Map对象是ES6中引入的JavaScript语法,Map对象的在存储中从健的类别的多类型和性能等方面都要比Object对象要优雅。介绍了Map对象,然后通过哈希相关算法题来加强巩固知识。通过上面算法题的练习我们发现使用map对象可以高效的查出数组中的一些特定条件内容。
看完三件事!!!
graph TD
点赞 --> 关注-->评论