当前位置: 首页 > news >正文

JavaScript系列(9)-- Set数据结构专题

JavaScript Set数据结构专题 🎲

在前八篇文章中,我们探讨了JavaScript的语言特性、ECMAScript标准、引擎工作原理、数值类型、字符串处理、Symbol类型、Object高级特性和Array高级操作。今天,让我们深入了解JavaScript中的Set数据结构。Set是ES6引入的一种新的集合类型,它允许你存储任何类型的唯一值。

Set基础概念 🌟

💡 小知识:Set是一个值的集合,其中的每个值只能出现一次。这个特性使它特别适合用于去重和集合运算。与Array不同,Set不是索引集合,它更关注值的唯一性。

Set的创建和基本操作 📊

// 1. Set的创建方式
function setCreation() {// 空Setconst set1 = new Set();// 从数组创建const set2 = new Set([1, 2, 3, 3, 4]); // 重复的3只会保留一个// 从字符串创建const set3 = new Set('hello'); // Set(4) {'h', 'e', 'l', 'o'}// 从其他可迭代对象创建const map = new Map([['a', 1], ['b', 2]]);const set4 = new Set(map.keys());// 基本操作set1.add(1);           // 添加值set1.delete(1);        // 删除值set1.has(1);          // 检查值是否存在set1.clear();         // 清空Setconsole.log(set1.size); // 获取大小
}// 2. Set的迭代
function setIteration() {const set = new Set(['a', 'b', 'c']);// forEach方法set.forEach((value, valueAgain, set) => {console.log(value); // value和valueAgain是相同的});// for...of循环for (const value of set) {console.log(value);}// 转换为数组const array = [...set];const array2 = Array.from(set);// 获取迭代器const values = set.values();const entries = set.entries();// entries()返回[value, value]形式的条目for (const [value1, value2] of entries) {console.log(value1 === value2); // true}
}// 3. Set的值比较
function setValueComparison() {const set = new Set();// NaN的处理set.add(NaN);set.add(NaN);console.log(set.size); // 1,NaN被认为是相同的值// +0和-0的处理set.add(+0);set.add(-0);console.log(set.size); // 1,+0和-0被认为是相同的值// 对象的处理const obj1 = { id: 1 };const obj2 = { id: 1 };set.add(obj1);set.add(obj2);console.log(set.size); // 2,不同对象被认为是不同的值
}

Set的高级操作 🔧

// 1. 集合运算
class SetOperations {// 并集static union(setA, setB) {return new Set([...setA, ...setB]);}// 交集static intersection(setA, setB) {return new Set([...setA].filter(x => setB.has(x)));}// 差集static difference(setA, setB) {return new Set([...setA].filter(x => !setB.has(x)));}// 对称差集static symmetricDifference(setA, setB) {return new Set([...setA].filter(x => !setB.has(x)).concat([...setB].filter(x => !setA.has(x))));}// 子集检查static isSubset(setA, setB) {return [...setA].every(x => setB.has(x));}// 超集检查static isSuperset(setA, setB) {return [...setB].every(x => setA.has(x));}
}// 2. 自定义Set操作
class CustomSet extends Set {// 添加多个值addMany(...items) {items.forEach(item => this.add(item));return this;}// 删除多个值deleteMany(...items) {items.forEach(item => this.delete(item));return this;}// 过滤操作filter(callback) {const filteredSet = new CustomSet();for (const value of this) {if (callback(value)) {filteredSet.add(value);}}return filteredSet;}// 映射操作map(callback) {const mappedSet = new CustomSet();for (const value of this) {mappedSet.add(callback(value));}return mappedSet;}// 转换为对象toObject(keyFn = value => value) {const obj = {};for (const value of this) {obj[keyFn(value)] = value;}return obj;}
}// 3. Set与数组的互操作
class SetArrayOperations {// 数组去重static uniqueArray(arr) {return [...new Set(arr)];}// 查找重复元素static findDuplicates(arr) {const seen = new Set();const duplicates = new Set();arr.forEach(item => {if (seen.has(item)) {duplicates.add(item);} else {seen.add(item);}});return duplicates;}// 保持插入顺序的唯一化static uniqueOrdered(arr) {return Array.from(new Set(arr));}
}

Set的实际应用 💼

让我们看看Set在实际开发中的一些应用场景:

// 1. 标签系统
class TagSystem {constructor() {this.tagSets = new Map();}// 添加标签addTags(itemId, ...tags) {if (!this.tagSets.has(itemId)) {this.tagSets.set(itemId, new Set());}tags.forEach(tag => this.tagSets.get(itemId).add(tag));}// 移除标签removeTags(itemId, ...tags) {const tagSet = this.tagSets.get(itemId);if (tagSet) {tags.forEach(tag => tagSet.delete(tag));}}// 获取具有特定标签的项目getItemsWithTags(...tags) {const items = [];for (const [itemId, tagSet] of this.tagSets) {if (tags.every(tag => tagSet.has(tag))) {items.push(itemId);}}return items;}// 获取相关标签getRelatedTags(tag) {const relatedTags = new Set();for (const tagSet of this.tagSets.values()) {if (tagSet.has(tag)) {tagSet.forEach(t => {if (t !== tag) relatedTags.add(t);});}}return relatedTags;}
}// 2. 用户权限系统
class PermissionSystem {constructor() {this.userPermissions = new Map();this.rolePermissions = new Map();}// 添加角色权限addRolePermissions(role, ...permissions) {if (!this.rolePermissions.has(role)) {this.rolePermissions.set(role, new Set());}permissions.forEach(perm => this.rolePermissions.get(role).add(perm));}// 分配用户角色assignUserRoles(userId, ...roles) {if (!this.userPermissions.has(userId)) {this.userPermissions.set(userId, new Set());}const userPerms = this.userPermissions.get(userId);roles.forEach(role => {const rolePerms = this.rolePermissions.get(role);if (rolePerms) {rolePerms.forEach(perm => userPerms.add(perm));}});}// 检查权限hasPermission(userId, permission) {const userPerms = this.userPermissions.get(userId);return userPerms ? userPerms.has(permission) : false;}
}// 3. 缓存系统
class CacheSystem {constructor(maxSize = 1000) {this.maxSize = maxSize;this.cache = new Map();this.accessOrder = new Set();}get(key) {if (this.cache.has(key)) {// 更新访问顺序this.accessOrder.delete(key);this.accessOrder.add(key);return this.cache.get(key);}return null;}set(key, value) {if (this.cache.size >= this.maxSize && !this.cache.has(key)) {// 移除最早访问的项const oldestKey = this.accessOrder.values().next().value;this.accessOrder.delete(oldestKey);this.cache.delete(oldestKey);}this.cache.set(key, value);this.accessOrder.delete(key);this.accessOrder.add(key);}
}

性能优化 ⚡

处理Set时的一些性能优化技巧:

// 1. Set大小优化
function setSizeOptimization() {// 预分配合适的大小const initialData = new Array(1000).fill(0).map((_, i) => i);// 一次性创建Setconst set = new Set(initialData);  // 比循环添加更快// 避免频繁修改const tempArray = [];for (let i = 0; i < 1000; i++) {tempArray.push(i);}const set2 = new Set(tempArray);
}// 2. Set操作优化
class OptimizedSetOperations {// 优化的交集操作static optimizedIntersection(setA, setB) {// 选择较小的集合进行迭代const [smaller, bigger] = setA.size < setB.size ? [setA, setB] : [setB, setA];return new Set([...smaller].filter(x => bigger.has(x)));}// 批量操作优化static batchAdd(set, items) {const tempSet = new Set(set);items.forEach(item => tempSet.add(item));return tempSet;}
}// 3. 内存优化
class MemoryEfficientSet {constructor() {this.set = new Set();this.weakRefs = new WeakMap();}addObject(obj) {const ref = new WeakRef(obj);this.weakRefs.set(obj, ref);this.set.add(ref);}hasObject(obj) {const ref = this.weakRefs.get(obj);return ref && this.set.has(ref) && ref.deref() === obj;}
}

最佳实践建议 💡

  1. Set使用场景
// 1. 数据去重
function deduplication() {// 基本类型去重const numbers = [1, 2, 2, 3, 3, 4];const uniqueNumbers = [...new Set(numbers)];// 对象去重const objects = [{ id: 1, name: 'A' },{ id: 1, name: 'A' },{ id: 2, name: 'B' }];const uniqueById = [...new Set(objects.map(obj => JSON.stringify(obj)))].map(str => JSON.parse(str));
}// 2. 集合运算
function setOperations() {const set1 = new Set([1, 2, 3]);const set2 = new Set([2, 3, 4]);// 并集const union = new Set([...set1, ...set2]);// 交集const intersection = new Set([...set1].filter(x => set2.has(x)));// 差集const difference = new Set([...set1].filter(x => !set2.has(x)));
}// 3. 唯一性检查
function uniquenessChecking() {const visited = new Set();function isUnique(item) {if (visited.has(item)) return false;visited.add(item);return true;}
}
  1. 错误处理和验证
// 1. Set验证
function validateSet(set) {if (!(set instanceof Set)) {throw new TypeError('参数必须是Set类型');}if (set.size === 0) {throw new Error('Set不能为空');}return true;
}// 2. 安全的Set操作
function safeSetOperations() {function safeAdd(set, value) {try {set.add(value);return true;} catch (error) {console.error('添加值失败:', error);return false;}}function safeDelete(set, value) {try {return set.delete(value);} catch (error) {console.error('删除值失败:', error);return false;}}
}// 3. 类型检查
function setTypeChecking() {function isNumberSet(set) {return set instanceof Set && [...set].every(x => typeof x === 'number');}function isObjectSet(set) {return set instanceof Set && [...set].every(x => x && typeof x === 'object');}
}

结语 📝

JavaScript的Set数据结构为我们提供了一种优雅的方式来处理唯一值的集合。我们学习了:

  1. Set的基本概念和操作
  2. Set的高级操作和扩展
  3. 实际应用场景
  4. 性能优化技巧
  5. 最佳实践和注意事项

💡 学习建议:在使用Set时,要充分利用其唯一性特征,选择合适的场景使用。注意Set的值比较规则,特别是在处理对象时。同时,要考虑性能影响,合理使用Set的各种操作方法。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

http://www.lryc.cn/news/516887.html

相关文章:

  • 开发培训-慧集通(iPaaS)集成平台脚本开发Groovy基础培训视频
  • 【软考网工笔记】计算机基础理论与安全——网络规划与设计
  • 【设计模式】 基本原则、设计模式分类
  • mac m2 安装 docker
  • Vue3-pinia的具体使用和刷新页面状态保持解决方案
  • 用ResNet50+Qwen2-VL-2B-Instruct+LoRA模仿Diffusion-VLA的论文思路,在3090显卡上训练和测试成功
  • 创建.net core 8.0项目时,有个启用原生AOT发布是什么意思
  • 2.1.7-1 io_uring的使用
  • 群论学习笔记
  • 深入解析-正则表达式
  • yolov5核查数据标注漏报和误报
  • 日志聚类算法 Drain 的实践与改良
  • 如何让用户在网页中填写PDF表格?
  • GXUOJ-算法-补题:22级《算法设计与分析》第一次课堂练习
  • 源代码编译安装X11及相关库、vim,配置vim(3)
  • uniapp 微信小程序 自定义日历组件
  • EdgeX规则引擎eKuiper
  • react 优化方案
  • 【Linux】sed编辑器
  • (leetcode算法题)137. 只出现一次的数字 II
  • 在大数据环境下高效运用NoSQL与关系型数据库的结合策略
  • C语言——分支与循环语句
  • 下载b站高清视频
  • 常见 JVM垃圾回收器、内存分配策略、JVM调优
  • 【HarmonyOS应用开发——ArkTS语言】欢迎界面(启动加载页)的实现【合集】
  • 【MySQL】:Linux 环境下 MySQL 使用全攻略
  • Linux驱动开发 gpio_get_value读取输出io的电平返回值一直为0的问题
  • 【数据结构】栈与队列(FIFO)
  • vue.js -ref和$refs获取dom和组件
  • unity学习5:创建一个自己的3D项目