zoukankan      html  css  js  c++  java
  • 数组去重

    题目描述

    编写一个Javascript函数,传入一个数组,对数组中的元素进行去重并返回一个无重复元素的数组,数组的元素可以是数字、字符串、数组和对象。举例说明:
    1. 如传入的数组元素为[123, "meili", "123", "mogu", 123],则输出:[123, "meili", "123", "mogu"]
    2. 如传入的数组元素为[123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"],则输出:[123, [1, 2, 3], [1, "2", 3], "meili"]
    3. 如传入的数组元素为[123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"],则输出:[123, {a: 1}, {a: {b: 1}}, {a: "1"}, "meili"]

    第一种解法:map+Set

    把数组中的对象解析成字符串的方法用的是JSON.stringify()方法

    		var arr1 = [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"];
            var arr2 = [123, "meili", "123", "mogu", 123];
            var arr3 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];
    
            function unique(arr) {
                var  b = arr.map(item=>{
                    return JSON.stringify(item);//JSON.stringify(item)是把数组中的对象解析成字符串再比较
                 })
                 var c = Array.from(new Set(b));//Set(b)用来对b去重,但是去重后的结果不是我们想要的数组的形式,所以需要用 Array.from()的方法变成我们想要的数组的形式
                 var d = c.map(item=>{
                    return JSON.parse(item);
                 })
                 return  d;
    
            console.log(unique(arr1));
            console.log(unique(arr2));
            console.log(unique(arr3));
    

    1567576782074

    1.1 filter

    使用filter代替map,结果出来的结果不是想要的

    1567577357121

    注意:filter返回的是filter返回的是在一定条件下返回值为true的原数组项,所以此处最适合的是map或者for循环

    所以如果需要从原数组中返回满足一定条件的数组,可以使用filter。

    1.2 map和filter

    红宝书中是这样描述的:

    • filter()----创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
    • map()----返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。按照原始数组元素顺序依次处理元素。

    1.3 map和foreach

    相同点

    • 都是会遍历数组的每一个元素,
    • 同样是三个参数
    • 都是只能遍历数组

    不同点

    • forEach()方法不会返回执行结果,而是undefined,红宝书中说的是没有返回值
    • 而map()方法会得到一个新的数组并返回

    使用场景

    • forEach适合于你并不打算改变数据的时候,而只是想用数据做一些事情 – 比如存入数据库或则打印出来
    • map()适用于你要改变数据值的时候。不仅仅在于它更快,而且返回一个新的数组

    forEach到底会不会改变原数组

    1.4 Array.from

    Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)

    1.4.1 将两类对象转化为真正的数组

    • 类数组对象所谓类似数组的对象,本质特征只有一点,即必须有length属性

      let arrayLike = {
          '0': 'a',
          '1': 'b',
          '2': 'c',
          length: 3
      };
      
      // ES5的写法
      var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']
      
      // ES6的写法
      let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
      

      关于call的思考

    • 只要是部署了 Iterator 接口的数据结构,Array.from都能将其转为数组。

      Array.from('hello')
      // ['h', 'e', 'l', 'l', 'o']
      
      let namesSet = new Set(['a', 'b'])
      Array.from(namesSet) // ['a', 'b']
      

      补充:扩展运算符(...)也可以将某些数据结构转为数组。扩展运算符背后调用的是遍历器接口(Symbol.iterator),因此只要具有 Iterator 接口的对象,都可以使用扩展运算符

      let nodeList = document.querySelectorAll('div');
      let array = [...nodeList];
      

      上面代码中,querySelectorAll方法返回的是一个NodeList对象。它不是数组,而是一个类似数组的对象。这时,扩展运算符可以将其转为真正的数组,原因就在于NodeList对象实现了 Iterator

      • 比如 Map 结构是具有 Iterator 接口的对象,可以使用扩展运算符
      let map = new Map([
        [1, 'one'],
        [2, 'two'],
        [3, 'three'],
      ]);
      
      let arr = [...map.keys()]; // [1, 2, 3]
      
      • Generator 函数运行后,返回一个遍历器对象,因此也可以使用扩展运算符。
      const go = function*(){
        yield 1;
        yield 2;
        yield 3;
      };
      
      [...go()] // [1, 2, 3]
      

      上面代码中,变量go是一个 Generator 函数,执行后返回的是一个遍历器对象,对这个遍历器对象执行扩展运算符,就会将内部遍历得到的值,转为一个数组。

      • 如果对没有 Iterator 接口的对象,使用扩展运算符,将会报错。
      const obj = {a: 1, b: 2};
      let arr = [...obj]; // TypeError: Cannot spread non-iterable object
      
    • 本身是数组的话

      Array.from([1, 2, 3])
      // [1, 2, 3]
      

    1.4.2 Array.from还可以接受第二个参数

    作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

    Array.from(arrayLike, x => x * x);
    // 等同于
    Array.from(arrayLike).map(x => x * x);
    
    Array.from([1, 2, 3], (x) => x * x)
    // [1, 4, 9]
    
    

    1.4.3 如果map函数里面用到了this关键字,还可以传入Array.from的第三个参数,用来绑定this

    1.4.4 将字符串转为数组,然后返回字符串的长度

    function countSymbols(string) {
      return Array.from(string).length;
    }
    
    

    第二种解法 :双重遍历

    思想:通过拿出一个元素和剩下的元素依次比较,如果全部不相等则证明此元素为唯一

    var arr1 = [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"];
            var arr3 = [123, "meili", "123", "mogu", 123];
            var arr2 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];
    
            function unique(arr) {
                let b=[]
                for(let i=0;i<arr.length;i++){
                    let unexit=true
                    for(let j=i+1;j<arr.length;j++){
                        if(JSON.stringify(arr[i])===JSON.stringify(arr[j])){
                            unexit=false
                            break
                        }
                        else{
                            unexit=true
                        }
                    }
                    if(unexit){
                        b.push(arr[i])
                    }
                }
                return b
                
            }
    
            console.log(unique(arr1));
            console.log(unique(arr2));
            console.log(unique(arr3));
    
    

    1567588248415

    缺点:顺序会改变

    第三种解法:Object.keys():存在唯一性

            var arr1 = [123, {a: 1}, {a: {b: 1}}, {a: "1"}, {a: {b: 1}}, "meili"];
            var arr3 = [123, "meili", "123", "mogu", 123];
            var arr2 = [123, [1, 2, 3], [1, "2", 3], [1, 2, 3], "meili"];
    
            function unique(arr) {
                let b=[]
                let hash={}
                for(let i=0;i<arr.length;i++){
                    if(!hash[JSON.stringify(arr[i])]){
                        hash[JSON.stringify(arr[i])]=true
                        b.push(arr[i])
                    }
                }
                return b    
            }
    
            console.log(unique(arr1));
            console.log(unique(arr2));
            console.log(unique(arr3));
    
    

    这三种方法都可以实现对象去重,第二种存在一些缺点,顺序会改变。

    参考:https://www.jb51.net/article/134411.htm

    http://es6.ruanyifeng.com/#docs/set-map#Map

    https://juejin.im/post/5ca7514a6fb9a05e790a46a4

  • 相关阅读:
    【转载】最常见的数据类型映射列表
    【自然框架 NatureFramework】 项目结构、命名空间和命名规范
    【自然框架之SSO】实现SSO的一个初步想法
    两张图说明三层的奥义!
    Android中文API(146) —— Display
    [视频监控][海康威视]二次开发 网友文章转载贴
    Android中文API(141) —— GridLayout
    Android支持横行滚动的ListView控件
    Android应用开发提高系列(5)——Android动态加载(下)——加载已安装APK中的类和资源
    [WinForm]DataGridView通过代码新增行问题
  • 原文地址:https://www.cnblogs.com/zhoujingguoguo/p/11539655.html
Copyright © 2011-2022 走看看