扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
这篇“JavaScript怎么实现数组去重”文章,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要参考一下,对于“JavaScript怎么实现数组去重”,小编整理了以下知识点,请大家跟着小编的步伐一步一步的慢慢理解,接下来就让我们进入主题吧。
创新互联公司成立以来不断整合自身及行业资源、不断突破观念以使企业策略得到完善和成熟,建立了一套“以技术为基点,以客户需求中心、市场为导向”的快速反应体系。对公司的主营项目,如中高端企业网站企划 / 设计、行业 / 企业门户设计推广、行业门户平台运营、手机APP定制开发、手机网站制作设计、微信网站制作、软件开发、温江服务器托管等实行标准化操作,让客户可以直观的预知到从创新互联公司可以获得的服务效果。1.JavaScript主要用来向HTML页面添加交互行为。 2.JavaScript可以直接嵌入到HTML页面,但写成单独的js文件有利于结构和行为的分离。 3.JavaScript具有跨平台特性,在绝大多数浏览器的支持下,可以在多种平台下运行。
一、双层循环
const unique = (arr)=>{ for(let i = 0; i < arr.length; i++){ for(let j = i + 1; j < arr.length; j++){ if(arr[i] === arr[j]){ arr.splice(j, 1); // 移除重复元素 j--; // 修正下标 } } } return arr;};const unique = (arr)=>{ var arr = [1, '1', '1', 1, 2, true, false, true, 3, 2, 2, 1]; var newArr = []; for(let i = 0; i < arr.length; i++){ for(var j = 0; j < newArr.length; j++){ // 注意var声明的j if(arr[i] === newArr[j]) break; // 新数组已存在当前值 } if(j === newArr.length){ // 此时j和newArr长度相等,没有被中断 newArr.push(arr[i]); } } return newArr;}unique([1, '1', '1', 1, 2, true, false, true, 3, 2, 2, 1]); // [ 1, '1', 2, true, false, 3 ]
核心点:
时间复杂度:O(n^2)
上面的两种方法都是两次循环遍历,处理方式略有不同
上述实现方式确实不是很好选择,但它胜在兼容性好啊~
二、indexOf和includes
核心点:
如果需要返回原数组,则可以在indexOf
方法找到重复项时(不等于它首次出现的位置)时利用splice
移除
indexOf
:返回在数组中可以找到一个给定元素的第一个索引
,如果不存在,则返回-1。
indexOf(ele, fromIndex)
ele:要查找的元素
fromIndex:查找元素的起始位置,默认为0,允许负数,-2表示从倒数第二个元素开始查找
返回一个下标(number)
代码:
const unique = (arr) => { var res = []; for (let i = 0; i < arr.length; i++){ if(res.indexOf(arr[i]) === -1 ){ res.push(arr[i]); } } return res;}
核心点:
具体的是要返回原数组还是新数组大家可以自行组合~
includes
:用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true
,否则返回false
includes(ele, fromIndex)
ele:要查找的元素
fromIndex:指定索引处开始查找。默认为 0,如果为负值,从末尾开始往前跳fromIndex
的绝对值个索引。。
返回结果(bool)
代码:
const unique = (arr) => { var res = []; for (let i = 0; i < arr.length; i++){ if(!res.includes(arr[i])){ res.push(arr[i]); } } return res;}
在这里我们推荐使用includes来查找元素:
返回值可以直接作为if的条件语句,简洁
if(res.indexOf(arr[i]) !== -1 ){ todo }// orif(res.includes(arr[i])){ todo }
识别NaN
如果数组中有NaN
,你又正好需要判断数组是否有存在NaN
,这时你使用indexOf
是无法判断的,你必须使用includes
这个方法。
var arr = [NaN, NaN];arr.indexOf(NaN); // -1arr.includes(NaN); // true
识别undefined
如果数组中有undefined
值,includes
会认为空的值是undefined,而indexOf
不会。
var arr = new Array(3);console.log(arr.indexOf(undefined)); //-1console.log(arr.includes(undefined)) //true
三、排序去重
核心点:
数组排序后,相同的元素会相邻,所以如果当前元素与它的相邻元素不同,就存入到新数组中;
相比于indexOf,只需要一层循环;
concat会拼接数组,并返回新数组;
sort()排序是通过按照转换为的字符串的各个字符的Unicode位点
进行排序。所以很难保证它的准确性;
代码:
var arr = [1, 1, '1'];function unique(arr) { var res = []; var sortedArr = arr.concat().sort(); var last; for (var i = 0; i < sortedArr.length ; i++) { // 如果是第一个元素或者相邻的元素不相同 if (!i || last !== sortedArr[i]) { res.push(sortedArr[i]) } last = sortedArr[i]; // 记录上一个值 } return res;}console.log(unique(array));
四、filter
核心点:
filter:方法创建一个新数组, 其包含通过所提供函数实现的测试
的所有元素(返回测试函数成立的元素)
filter(callback, thisArg)
:
callback接受三个参数:element-当前正在处理的元素,index-当前元素索引,array-调用了filter的数组本身
thisArg:执行 callback 时,用于 this 的值。
利用filter我们可以在代码层面简化一下外层循环:
代码:
var arr = [1, 2, 1, 1, '1'];const unique = function (arr) { var res = arr.filter(function(item, index, arr){ return arr.indexOf(item) === index; }) return res;}console.log(unique(arr)); // [ 1, 2, '1' ]
结合排序的思路:
var arr = [1, 2, 1, 1, '1'];const unique = function (arr) { return arr.concat().sort().filter(function(item, index, arr){ return !index || item !== arr[index - 1] })}console.log(unique(arr));
五、键值对(key-value)
前面提到的几种方式总结下来大致分为
非排序数组,两次遍历判断(遍历、查询)
排序数组,相邻元素比较
我们再提出一种方式,利用Object对象 key-value的方式,来统计数组中元素出现的个数,初步判断逻辑也有两种
拿[1,1,1,2,2,3,'3']
举例:
统计每个元素出现的次数,obj:{1: 3, 2: 2, 3: 3}, 返回这个obj
的key
而不管他们的value
只元素首次出现,再次出现则证明他是重复元素
var arr = [1, 2, 1, 1, '1', 3, 3];const unique = function(arr) { var obj = {}; var res = []; arr.forEach(item => { if (!obj[item]) { obj[item] = true; res.push(item); } }); return res;}console.log(unique(arr)); // [1, 2, 3]
var arr = [1, 2, 1, 1, '1'];const unique = function(arr) { var obj = {}; return arr.filter(function(item, index, arr){ return obj.hasOwnProperty(item) ? false : (obj[item] = true) })}console.log(unique(arr)); // [1, 2]
对象的属性是字符串类型的,即本身数字1
和字符串‘1’
是不同的,但保存到对象中时会发生隐式类型转换,导致去重存在一定的隐患。
考虑到string和number的区别(typeof 1 === ‘number’, typeof ‘1’ === ‘string’),
所以我们可以使用typeof item + item
拼成字符串作为 key 值来避免这个问题:
var arr = [1, 2, 1, 1, '1', 3, 3, '2'];const unique = function(arr) { var obj = {}; var res = []; arr.forEach(item => { if (!obj[typeof item + item]) { obj[typeof item + item] = true; res.push(item); } }); return res;}console.log(unique(arr)); // [ 1, 2, '1', 3, '2' ]
六、ES6
随着 ES6 的到来,去重的方法又有了进展,比如我们可以使用 Set 和 Map 数据结构。
Set:它允许你存储任何类型的值,无论是原始值或者是对象引用
代码:
var arr = [1, 2, 1, '1', '2'];const unique = function(arr) { return Array.from(new Set(arr));}console.log(unique(arr)); // [ 1, 2, '1', '2' ]
简化1:
function unique(array) { return [...new Set(array)];}
简化2:
var unique = (a) => [...new Set(a)]
Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。
Map.prototype.has(key):返回一个布尔值,表示Map实例是否包含键对应的值。
Map.prototype.set(key, value):设置Map对象中键的值。返回该Map对象。
function unique (arr) { const newMap = new Map() return arr.filter((a) => !newMap.has(a) && newMap.set(a, 1));}
写到这里比较常规的数组去重方法就总结的差不多了,如果需要更强大的去重方法,我们需要对他们进行组合,而且因为场景的不同,我们所实现的方法并不一定能涵盖到
以上是“JavaScript怎么实现数组去重”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流