美文网首页
老生常谈问题之数组去重

老生常谈问题之数组去重

作者: 埃米莉Emily | 来源:发表于2017-09-28 14:33 被阅读77次

排序去重

思路:

  • 先将原数组进行排序
  • 检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序,所以重复元素会在相邻位置
  • 如果不相同,则将该元素存入结果数组中
function unique (arr){
    this.sort()
    let res = [this[0]]
    for (var i = 1; i < this.length; i++) {
      if (this[i] !== res[res.length - 1]) {
      res.push(this[i]);
      }
    }
    return res
}
const arr = [1, 'a', 'm', 'c', 'd', 'e', 'e', 1, 0, -1]
alert(unique(arr))

双层循环去重

思路:

  • 我们使用循环嵌套,最外层循环 array,里面循环 res,如果 array[i] 的值跟 res[j] 的值相等,就跳出循环,如果都不等于,说明元素是唯一的,这时候 j 的值就会等于 res 的长度,根据这个特点进行判断,将值添加进 res。
let array = [1, 'a', 'm', 'c', 'd', 'e', 'e', 1, 0, -1]

function unique(array) {
    // res用来存储结果
    let res = []
    for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
        for (var j = 0, resLen = res.length; j < resLen; j++ ) {
            if (array[i] === res[j]) {
                break
            }
        }
        if (j === resLen) {
            res.push(array[i])
        }
    }
    return res
}

console.log(unique(array))

indexOf 去重

思路:

  • 用 indexOf 简化内层的循环:
const array = [1, 'a', 'm', 'c', 'd', 'e', 'e', 1, 0, -1]

function unique(array) {
    var res = [];
    for (var i = 0, len = array.length; i < len; i++) {
        var current = array[i];
        if (res.indexOf(current) === -1) {
            res.push(current)
        }
    }
    return res;
}

console.log(unique(array))

unique API

思路:

  • 知道了这两种方法后,我们可以去尝试写一个名为 unique 的工具函数,我们根据一个参数 isSorted 判断传入的数组是否是已排序的,如果为 true,我们就判断相邻元素是否相同,如果为 false,我们就使用 indexOf 进行判断。
var array1 = [1, 2, '1', 2, 1];
var array2 = [1, 1, '1', 2, 2];

// 第一版
function unique(array, isSorted) {
    var res = [];
    var seen = [];

    for (var i = 0, len = array.length; i < len; i++) {
        var value = array[i];
        if (isSorted) {
            if (!i || seen !== value) {
                res.push(value)
            }
            seen = value;
        }
        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }
    return res;
}

console.log(unique(array1)); // [1, 2, "1"]
console.log(unique(array2, true)); // [1, "1", 2]

优化

尽管 unqique 已经可以试下去重功能,但是为了让这个 API 更加强大,我们来考虑一个需求:

新需求:字母的大小写视为一致,比如'a'和'A',保留一个就可以了!

虽然我们可以先处理数组中的所有数据,比如将所有的字母转成小写,然后再传入unique函数,但是有没有方法可以省掉处理数组的这一遍循环,直接就在去重的循环中做呢?让我们去完成这个需求:

const array3 = [1, 1, 'a', 'A', 2, 2];

// 第二版
// iteratee 英文释义:迭代 重复
function unique(array, isSorted, iteratee) {
    let res = [];
    let seen = [];

    for (var i = 0, len = array.length; i < len; i++) {
        let value = array[i];
        let computed = iteratee ? iteratee(value, i, array) : value;
        if (isSorted) {
            if (!i || seen !== value) {
                res.push(value)
            }
            seen = value;
        }
        else if (iteratee) {
            if (seen.indexOf(computed) === -1) {
                seen.push(computed);
                res.push(value);
            }
        }
        else if (res.indexOf(value) === -1) {
            res.push(value);
        }        
    }
    return res;
}

console.log(unique(array3, false, function(item) {
    return typeof item == 'string' ? item.toLowerCase() : item
}))

在这一版也是最后一版的实现中,函数传递三个参数:

array:表示要去重的数组,必填

isSorted:表示函数传入的数组是否已排过序,如果为 true,将会采用更快的方法进行去重

iteratee:传入一个函数,可以对每个元素进行重新的计算,然后根据处理的结果进行去重

filter

ES5 提供了 filter 方法,我们可以用来简化外层循环:

比如使用 indexOf 的方法:

const array = [1, 2, 1, 1, '1']

function unique(array) {
    return array.filter(function(item, index, array){
        return array.indexOf(item) === index;
    })
}

console.log(unique(array))

排序去重的方法:

const array = [1, 2, 1, 1, '1']

function unique(array) {
    return array.concat().sort().filter(function(item, index, array){
        return !index || item !== array[index - 1]
    })
}

console.log(unique(array))

ES6

随着 ES6 的到来,去重的方法又有了进展,比如我们可以使用 Set 和 Map 数据结构,以 Set 为例,ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。

是不是感觉就像是为去重而准备的?让我们来写一版:

const array = [1, 2, 1, 1, '1']

function unique(array) {
   return Array.from(new Set(array))
}

console.log(unique(array))

甚至可以再简化下:

function unique(array) {
    return [...new Set(array)];
}

还可以再简化下:

var unique = (a) => [...new Set(a)]

此外,如果用 Map 的话:

function unique (arr) {
    const seen = new Map()
    return arr.filter((a) => !seen.has(a) && seen.set(a, 1))
}

JavaScript 的进化

我们可以看到,去重方法从原始的 14 行代码到 ES6 的 1 行代码,其实也说明了 JavaScript 这门语言在不停的进步,相信以后的开发也会越来越高效。

相关文章

  • 老生常谈问题之数组去重

    排序去重 思路: 先将原数组进行排序 检查原数组中的第i个元素 与 结果数组中的最后一个元素是否相同,因为已经排序...

  • 『JavaScript专题』之数组去重

    JavaScript专题之数组去重 前言 数组去重方法老生常谈,既然是常谈,我也来谈谈。 双层循环 也许我们首先想...

  • JavaScript 数组去重的多种方法原理详解

    JavaScript 数组去重的多种方法原理详解 说明 数组去重,这是一个面试经常会遇见的问题,网上讲数组去重的文...

  • JS数组去重你会几种呀?

    前言 数组去重是一个老生常谈的话题,也是前端童鞋在面试时的一道高频题。本文将深入的探索数组去重的原理及实现,为各位...

  • 面试官在“逗”你系列:数组去重你会几种呀?

    前言 数组去重是一个老生常谈的话题,也是前端童鞋在面试时的一道高频题。本文将深入的探索数组去重的原理及实现,为各位...

  • JavaScript数组去重问题

    总结一下利用JS解决去重问题的方法。总体思路: 构建一个新的空数组。 遍历数组,将不重复的元素Push到新数组中。...

  • Java数组去重问题

    方法一: 使用两个标志位进行标定去重。此方法无需使用任何容器,也不需要另外开辟数组空间,推荐使用,但丢失了数组元素...

  • Array集结号

    实现数组去重的几种方法 数组去重一 数组去重二 利用数组indexof+push实现数组去重 数组去重三 利用对象...

  • JavaScript数组去重

    JavaScript中数组的常用操作之数组去重 方法一 方法二

  • 2020-01-19做些js的数组练习吧

    1.前端面试必问之数组去重 前端面试必问之数组去重 2.前端面试必问之深拷贝浅拷贝 3.

网友评论

      本文标题:老生常谈问题之数组去重

      本文链接:https://www.haomeiwen.com/subject/mromextx.html