Set和Map

什么是Set

Set我们可以叫做一种集合得数据结构

什么是Map

Map我们可以叫做一种字典得数据结构

那什么是集合?什么又是字典?

集合:是由一堆无序的、相关联的,而且不能重复的内存结构组成的组合

字典:是一些元素的集合。每个元素有一个称作key 的域,不同元素的key 各不相同

他们的共同点和不同点:

  • 共同点:集合、字典都可以存储不重复的值
  • 不同点:集合是以[值,值]的形式存储元素,字典是以[键,值]的形式存储

set 
// 初始化一个set数据结构
const set1 = new Set(); // 创建一个空set
const set2 =  new Set([1,2,3]); // 创建一个包含三个值的set
const set3 = new Set('abc'); // 创建一个包含三个字符的 Set
const set4 = new Set(new Map([['a', 1], ['b', 2]])); // 创建一个包含两个键值对的 Set
  • 使用 new Set() 创建一个空 Set
  • 使用 new Set(iterable) 创建一个包含 iterable 中所有值的 Set

着重注意一下第二个new Set(iterable)的这种形式,iterable是指可迭代的。

只要谈起数据结构,最基本的操作就是增删改查,Set相关常用的API如下:

  • add: 添加某个值(别乱想,添加只有各个方法,可别乱联想数组的push,那你可能数组用多了)
  • delete: 删除某个值
  • has:返回一个布尔值,表明是否含有这个值
  • clear:清空所有的成员

上面增删改查的API没啥好说的。

Set的大小或者说成员的个数是size属性,你可别来个length,length是数组的长度。

数据存在完了,我们要干啥呢?自然就是遍历数据:

Set提供的遍历方法

  • keys: 返回键名的遍历器
  • values: 返回键值的遍历器
  • entries:返回键值对的遍历器
  • forEach:使用回调函数遍历每个成员 (别大惊小怪,用forEach遍历数组,怎么人家Set就不能有)
  • for...of: 迭代Set中所有的成员
// 初始化一个set数据结构
const set1 = new Set(); // 创建一个空set
const set2 =  new Set([1,2,3]); // 创建一个包含三个值的set
const set3 = new Set('abc'); // 创建一个包含三个字符的 Set
const set4 = new Set(new Map([['a', 1], ['b', 2]])); // 创建一个包含两个键值对的 Set

// 一般来说比较常用的是values, entries,forEach, for...of方法

// forEach
set2.forEach(value => { console.log(value) });

//  for...of
for (const value of set2) { console.log(value) }

// values:  注意返回值是个遍历器,要遍历期中的数据才可以用
const iterator1 = set3.values();
for (const value of iterator1) { console.log(value) }

// entries:  返回的也是迭代器,只是迭代器每一项的值是数组[index, value]
const iterator2 = set2.entries();
for (const entry of iterator2) {console.log(entry) }

 

去重

Set数据结构中不允许重复的元素,利用这个特性可以很简洁的实现数组去重,不考虑性能的情况下,Set去重可以做到相当的简洁。

 [...new Set([1,2,3,3,1,2])]

 

交集 并集 差集 相等
const set1 = new Set([1, 2, 3]);
const set2 = new Set([2, 3, 4]);

// 交集
const intersection = new Set([...set1].filter(x => set2.has(x)));

const set1 = new Set([1, 2, 3]);
const set2 = new Set([2, 3, 4]);

// 并集
const union = new Set([...set1, ...set2]);

const set1 = new Set([1, 2, 3]);
const set2 = new Set([2, 3, 4]);

// 差集
const difference = new Set([...set1].filter(x => !set2.has(x)));

//相等
const set1 = new Set([1, 2, 3]);
const set2 = new Set([1, 2, 3]);

// 方法一:比较两个 Set 的大小和元素
console.log(set1.size === set2.size && [...set1].every(x => set2.has(x))); // true

// 方法二:使用 Set 的 `equals` 方法
console.log(set1.equals(set2)); // true

Map

  • 添加元素:大哥他不可是add哈,add可是人家Set的,它的是set,对的,使用 map.set(key, value) 添加一个键值对到 Map 中
  • 删除元素:使用 map.delete(key) 删除一个键值对从 Map 中。
  • 检查元素是否存在:使用 map.has(key) 检查 Map 中是否包含某个键。
  • 获取元素:使用 map.get(key) 获取某个键对应的值。大哥,map有这个get方法,Set可没有哈,记清楚了

map的长度跟Set一样,也是size属性,表示元素集合的个数。

数据存储完了,是不是要上遍历了,搞起来:

  • 使用 forEach 迭代 Map 中的所有键值对
  • 使用 for...of 迭代 Map 中的所有键值对
  • 使用 keys 方法获取 Map 中所有键的迭代器
  • 使用 values 方法获取 Map 中所有值的迭代器
  • 使用 entries 方法获取 Map 中所有键值对的迭代器
const map1 = new Map(); // 创建一个空 Map
const map2 = new Map([['a', 1], ['b', 2]]); // 创建一个包含两个键值对的 Map
const map3 = new Map(new Set([['a', 1], ['b', 2]])); // 创建一个包含两个键值对的 Map

// forEach,遍历键值对哈!三遍:键值对
map1.forEach((value, key) => { console.log(key, value)} );

// 同上
for (const [key, value] of map2) {console.log(key, value)}

// 所有的键
const keys = map3.keys();
for (const key of keys) {console.log(key) }

// 所有的值
const values = map3.values();
for (const value of values) { console.log(value) }

// 键值对
const entries = map3.entries();
for (const [key, value] of entries) { console.log(key, value) }

 

 

转换

怎么说呢,其实Map的转换是很常见的用法,一定要掌握的。

  • Map 转为数组:使用 [...map]Array.from(map) 将 Map 转换为数组。
  • 数组转为 Map:使用 new Map(iterable) 将数组转换为 Map。
  • Map 转为对象:使用 Object.fromEntries(map) 将 Map 转换为对象。
  • 对象转为 Map:使用 new Map(Object.entries(obj)) 将对象转换为 Map。

 

// map转换为数组
const arr = [...map1]; // [["a", 1]]
// 数组转换map
const map4 = new Map([['a', 1], ['b', 2]]);
// Map转换对象(这个有点意思哈,记住了,有用的)
const obj = Object.fromEntries(map4); // {a: 1, b: 2}
// 对象转换map
const map5 = new Map(Object.entries(obj)); // Map {a => 1, b => 2}
模拟字典

可以使用 Map 来模拟字典,键可以是单词,值可以是单词的定义。

 

const dictionary = new Map([
  ["apple", "一种水果"],
  ["banana", "一种水果"],
  ["cat", "一种动物"],
]);

console.log(dictionary.get("apple")); // "一种水果"

缓存数据

这个有点意思,可以使用 Map 来缓存数据,提高性能

const cache = new Map();

function getData(key) {
  if (cache.has(key)) {
    return cache.get(key);
  } else {
    const data = fetch(key);
    cache.set(key, data);
    return data;
  }
}

const data = getData("https://www.example.com");

 

对象去重

可以使用 Map 来对对象进行去重,例如只保留对象的 id 属性

const objects = [
  { id: 1, name: "John" },
  { id: 2, name: "Mary" },
  { id: 1, name: "Alice" },
];

const uniqueObjects = new Map();

for (const object of objects) {
  if (!uniqueObjects.has(object.id)) {
    uniqueObjects.set(object.id, object);
  }
}

console.log(uniqueObjects.values()); // [ { id: 1, name: "John" }, { id: 2, name: "Mary" } ]

 

统计元素次数

可以使用 Map 来统计元素出现的次数。

const words = ["a", "b", "c", "a", "b"];
const wordCounts = new Map();

for (const word of words) {
  if (wordCounts.has(word)) {
    wordCounts.set(word, wordCounts.get(word) + 1);
  } else {
    wordCounts.set(word, 1);
  }
}

// 上面的写法可以玩花活的,你懂的,娘希匹,反正我就觉得这种写法最好,可读性好高。(翻译成人话就是:我太菜了,这个才刚看明白,还花活,绕了我吧)

console.log(wordCounts); // Map { "a" => 2, "b" => 2, "c" => 1 }

 

 

实现 LRU 缓存

可以使用 Map 来实现 LRU 缓存,即最近最少使用缓存。

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }

  get(key) {
    if (this.cache.has(key)) {
      const value = this.cache.get(key);
      this.cache.delete(key);
      this.cache.set(key, value);
      return value;
    } else {
      return undefined;
    }
  }

  set(key, value) {
    if (this.cache.size === this.capacity) {
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    this.cache.set(key, value);
  }
}

const cache = new LRUCache(2);

cache.set("a", 1);
cache.set("b", 2);

console.log(cache.get("a")); // 1
cache.set("c", 3);

console.log(cache.get("b")); // undefined

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值