zoukankan      html  css  js  c++  java
  • ES6之新的数据结构

    Set

    Set 类似于数组,是一种集合的数据结构,和 Array 之间最大的区别是:

    • Set中所有的成员都是唯一的。
      可以把Set想象成是一个: 既没有重复元素,也没有顺序概念的数组。

    Set 本身是一个构造函数,用来生成 Set 数据结构

    const s1 = new Set();
    s1.add(5)
    s1.add(2).add(1).add(3).add(2).add(4)
    console.log(s1);
    

    Set 函数可接受一个可循环的数据结构(如数组、类数组、含有 iterable 接口的其他数据结构)作为参数来初始化

    const s2 = new Set([1, 2, 3, 4, 2, 3, 6])
    console.log(s2)
    

    对于对象,只对键值对中的键去重,值不去重,若重复,保留后放入的

    const s4 = new Set([{ "age": 17, "age": 18, "value": '张三', "value2": '张三', "name": '李刚' }, 1, 2, 3])
    console.log(s4)
    

    1.set属性及操作方法

    const s2 = new Set([1, 2, 3, 4, 2, 3, 6])
    console.log('========属性及操作方法============================');
    console.log(s2.size);   // set的长度
    console.log(s2.add('123')); // 向set中添加一个值,返回set结构本身,所以可使用链式结构
    console.log(s2.delete(3)); // 删除一个值,返回布尔值,表示是否删除成功
    console.log(s2.has(6)); // set中是否包含某个值,返回布尔值
    console.log(s2.has(3)); // set中是否包含某个值,返回布尔值
    console.log(s2.clear()); // 清除所有成员,无返回值
    console.log('====================================');
    

    2.set循环的方式

    const s3 = new Set(['a', 'b', 'c', 'd', '1', '2', 4, 5])
    console.log('==========循环==========================');
    console.log(s3);
    console.log(s3.keys());  // 返回键名
    console.log(s3.values()); // 返回键值
    console.log(s3.entries()); // 返回所有键值对成员
    console.log(s3.forEach(e => { // 遍历每一个成员
        console.log(e)
    }));
    console.log('====================================');
    

    set结构没有键名,只有键值(键名和键值是一个值),所以key方法和value方法的行为完全一致,entries方法返回的同时包括键名和键值,所以每次输出一个数组,它的两个成员完全相等。

    3. set应用
    3.1. 数组去重

    let array = [1, 2, 1, 3, 4, 4, 2, 7, 8]
    console.log('=====数组去重===============================');
    console.log([...new Set(array)]);
    console.log('====================================');
    

    3.2 实现并集,交集

    let a = new Set([1, 2, 3])
    let b = new Set([2, 3, 4])
    console.log('======并集/交集/差集==============================');
    console.log(new Set([...a, ...b]))
    console.log(new Set([...a].filter(x => b.has(x))))
    console.log(new Set([...a].filter(x => !b.has(x))))
    console.log('====================================');
    

    WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。

    • WeakSet 的成员只能是对象,而不能是其他类型的值。
    • WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。
    let w = new WeakSet([1, 2, 3])
    let w3 = new WeakSet([{ "age": 17 }])
    var obj = {}
    var sin = {}
    console.log('========WeakSet============================');
    // console.log(w);  // 报错
    console.log(typeof w3);
    console.log(w3.add({ "name": "张三" }));
    console.log(w3.size);
    // console.log(w3.keys()); // 报错
    console.log(w3.add(obj))
    console.log(w3.has(obj))
    console.log(w3.has(sin))
    console.log('====================================');
    

    - WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。
    - WeakSet 结构不可遍历。因为它的成员都是对象的弱引用,随时被回收机制回收,成员消失。所以WeakSet 结构不会有keys( ),values( ),entries( ),forEach( )等方法和size属性。

    Map

    Map和set类似

    Set,Map去重和数组去重的性能比较

    Array.from()方法从一个类似数组或可以迭代的对象中创建一个新的数组实例

    let arr1 = Array.from(new Array(100000), (x, index) => {
        return index
    })
    
    let arr2 = Array.from(new Array(50000), (x, index) => {
        return index + index
    })
    
    let start = new Date().getTime()
    console.log('开始数组去重')
    
    function distinct(a, b) {
        // 数组去重
    
        // 方法一
        // Array.filter() + indexOf
        // 这个方法的思路是,将两个数组拼接为一个数组,然后使用 ES6 中的 Array.filter() 遍历数组,并结合 indexOf 来排除重复项
    
        // let arr = a.concat(b);
        // return arr.filter((item, index) => {
        //     return arr.indexOf(item) === index
        // })
    
    
        // 方法二
        // 双重 for 循环
        // 外层循环遍历元素,内层循环检查是否重复
        // 当有重复值的时候,可以使用 push(),也可以使用 splice()
    
        // let arr = a.concat(b);
        // for (let i = 0, len = arr.length; i < len; i++) {
        //     for (let j = i + 1; j < len; j++) {
        //         if (arr[i] == arr[j]) {
        //             arr.splice(j, 1);
        //             // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一
        //             len--;
        //             j--;
        //         }
        //     }
        // }
        // return arr
    
    
        // 方法三 
        // for...of + includes()
        // 双重for循环的升级版,外层用 for...of 语句替换 for 循环,把内层循环改为 includes()
        // 先创建一个空数组,当 includes() 返回 false 的时候,就将该元素 push 到空数组中 
        // 类似的,还可以用 indexOf() 来替代 includes()
    
        // let arr = a.concat(b)
        // let result = []
        // for (let i of arr) {
        //     !result.includes(i) && result.push(i)
        // }
        // return result
    
        // 方法三和方法一类似,因此时长也接近
    
    
        // 方法四
        // Array.sort()
        // 比较相邻元素是否相等,从而排除重复项
    
        // let arr = a.concat(b)
        // arr = arr.sort()
        // let result = []
        // for (let i = 0; i < arr.length; i++) {
        //     arr[i] !== arr[i - 1] && result.push(arr[i])
        // }
        // return result
    
    
        // 方法五 Set
        // new Set() set的成员具有唯一性
    
        // return Array.from(new Set([...a, ...b]))
    
    
        // 方法六 Map
        // 如果res中没有某个键,就设置这个键的值为1
    
        // const arr = a.concat(b)
        // const res = new Map();
        // return arr.filter(item => !res.has(item) && res.set(item, 1))
    
    }
    
    console.log('去重后的长度', distinct(arr1, arr2).length)
    
    let end = new Date().getTime()
    console.log('耗时', end - start)
    

    通过对比,set,map去重性能更好

    Map,Set和数组的对比

    let map = new Map()
    let set = new Set();
    let array = []
    
    // 增
    map.set('t', 1);
    set.add({ t: 1 });
    array.push({ t: 1 })
    console.info('map-set-array', map, set, array);
    
    // 删
    map.delete('t');
    set.forEach(item => item.t ? set.delete(item) : '');
    let index = array.findIndex(item => item.t);
    array.splice(index, 1);
    console.info('map-set-array-empty', map, set, array);
    
    // 改
    map.set('t', 2);
    set.forEach(item => item.t ? item.t = 2 : '');
    array.forEach(item => item.t ? item.t = 2 : '');
    console.info('map-set-array-modify', map, set, array);
    
    // 查
    let map_exist = map.has('t');   // 时间复杂度O(1)
    let set_exist = set.has({ t: 1 });
    let array_exist = array.find(item => item.t); // O(n)
    console.info('map-set-array', map_exist, map_exist, array_exist);
    

    通过对比,map的API更加简单,Array需要遍历才能进行查,改,删的操作,set在进行删,改操作时也需要遍历。因此优先使用map

    Map、Set和Object对比

    let item = { t: 1 };
    let map = new Map();
    let set = new Set();
    let obj = {};
    
    // 增
    map.set('t', 1);
    map.set(3, 2);
    set.add(item);
    obj['t'] = 1;
    obj[3] = 2;
    console.info('map-set-obj', obj, map, set);
    
    // 删
    map.delete('t');
    set.delete(item);
    delete obj['t'];
    console.info('map-set-obj-empty', obj, map, set);
    
    // 改
    map.set('t', 2);
    item.t = 2;
    obj['t'] = 2;
    console.info('map-set-obj-modify', obj, map, set);
    
    // 查 
    console.info({
        map_exist: map.has('t'),
        set_exist: set.has(item),
        obj_exist: 't' in obj
    })
    
    

    通过对比可以发现:

    • 能使用map的优先使用,不使用数组
    • 考虑数据的唯一性,考虑使用set,不使用Object
  • 相关阅读:
    python数据集处理,加载成list
    *和multiply
    RuntimeWarning: overflow encountered in exp
    机器学习 回归
    argsort()
    transpose()、T
    numpy、matplotlib第三方库安装
    feedparser安装
    机器学习实战错误校正
    机器学习 基于概率论的分类方法:朴素贝叶斯
  • 原文地址:https://www.cnblogs.com/zppsakura/p/11724930.html
Copyright © 2011-2022 走看看