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

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

JavaScript Set数据结构专题 🎲

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

Set基础概念 🌟

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

Set的创建和基本操作 📊

// 1. Set的创建方式
function setCreation() {
    // 空Set
    const 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();         // 清空Set
    console.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);
    
    // 一次性创建Set
    const 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.kler.cn/a/472195.html

相关文章:

  • 鸿蒙中使用获取本地JSON文件
  • 牛客网刷题 ——C语言初阶(2分支和循环-for)——打印菱形
  • SpringBoot3集成案例
  • Flannel:Kubernetes 网络方案的“轻骑兵”
  • Burpsuite20241102macM1版安装
  • 三甲医院等级评审八维数据分析应用(一)--组织、制度、管理可视化篇
  • iOS - 消息机制
  • 数据结构(查找算法)
  • 深度学习中CUDA环境安装教程
  • 前端(API)学习笔记(CLASS 3):Dom事件进阶
  • Java-ClassPathResource读取包含JSON数据的txt文件
  • Linux操作系统——多线程互斥
  • MCU 和 PSK
  • #渗透测试#网络安全#一文了解什么是shell反弹!!!
  • MYSQL ------------MySQL 高级安装和升级 MySQL 中常用工具
  • Clisoft SOS与CAD系统集成
  • 从零手写缓存框架(二)redis expire 过期原理
  • Fastapi + vue3 自动化测试平台(1)--开篇
  • 接口项目操作图-thinkphp6-rabbitmq
  • 【动手学电机驱动】STM32-MBD(2)将 Simulink 模型部署到 STM32G431 开发板