一、问题描述:

var array=[1,45,3,1,4,67,45],请编写一个函数reDup来去掉其中的重复项,即

reDup(array);

console.log(array);//[1,45,3,4,67]

二、遍历的思路

首先,我们很自然想到,最终array数组得到了改变,我们可以使用引用类型的按值传递在内部改变arr的值。

因此,我们可以加入一个形式参数:

function reDup(arr){
}

当我们执行reDup(array)时,实际上array和reDup函数中的形式参数arr都指向内存中保存的同一个数组。

现在如何去掉其中的重复项呢?

首先,最容易想到的是遍历

从arr[0]开始,依次看后面的数组成员是否则与arr[0]相同,若相同,就删除。

第一轮:arr[1]、arr[2]…依次与arr[0]比较;

第二轮:arr[2]、arr[3]…依次与arr[1]比较;



第arr.length-1轮:arr[arr.length-2]与arr[arr.length-1]比较。

因此,我们不难写出如下代码:

function reDup(arr){
for(var i=0,len=arr.length;i<len-1;i++)
{
for(var j=i+1;j<len;j++)
{
if(arr[j]===arr[i])
{
arr.splice(j,1);
}
}
}
}

我们测试一下结果是否正确:

var array=[1,45,3,1,4,67,45];
reDup(array);
console.log(array);//[1, 45, 3, 4, 67]

我们看到结果符合预期。

三、遍历的问题

如果我们观察得更仔细一些,就会发现:

当我们进行第一轮和array[0]的比较,到array[3]和array[0]时,发现两者相同,便会删除array[3];

这样我们的数组变成[1,45,3,4,67,45],即原先的array[4]变成 了现在的array[3]。

下一次比较是array[4]和array[0]的比较,即原先的array[5]和array[0]的比较。

我们看到原先的array[4]和array[0]并没有进行比较。即:

每删除一项,就会导致被删除项的后一项未参与比较。

为什么我们的结果是正确的呢?

在我们上面的例子中,被删除项的后一项都与被删除项不相同,因此并不会影响结果,现在我们来看另外的例子:

var array=[1,45,3,1,1,1,4,67,45,45,45];
reDup(array);
console.log(array);//[1, 45, 3, 1, 4, 67, 45]

这里显然不是我们想要的结果。

执行array[0](值为1)与array[3]比较后,将删除array[3],原array[3]后面的项整体会向前移一位,下次比较是array[0]与array[4]的比较,实质上是array[0]和原array[5]的比较。当然,这里会删除原array[5]。但是原array[4]实际上并没有和array[0]比较,由于原array[4]和array[0]是相同的,故导致结果不正确。

我们可以得出结论:

每删除一项,就会导致被删除项的后一项未能参与比较,而更后面一项却又能正常比较。

四、遍历的改进

由上,改进的一种思路是强行让被删除项的后一项参与比较,若被删除项的后一项也与被删除项一致,将再次删除它。

这也导致新的问题:后面的所有项都要向前再移一个位置。

事实上,鉴于删除项的不确定性和数组项的索引位置被改变,我们可以改进为从后往前遍历:

function reDup(arr){
for(var i=0,len=arr.length;i<len-1;i++)
{
for(var j=len-1;j>i;j--)
{
if(arr[j]===arr[i])
{
arr.splice(j,1);
}
}
}
}
var array=[1,45,3,1,1,1,4,67,45,45,45];
reDup(array);
console.log(array);//[1, 45, 3, 4, 67]

结果符合预期。

五、边界条件判定

现在,我们还不能认为万事大吉了。一个问题时,对于一些特殊情况,函数是否也能返回正确值?

首先,假使数组为空数组:

len的值为0,循环一开始就不会执行,因此实际上函数什么也没做,最终还是空数组,结果符合预期。

假使数组仅有1项:

len的值为1,同样循环一开始就不会执行,函数什么也没做,最终还是原数组,结果符合预期。

即使数组有2项:

len的值为2,外层循环执行1次,内层循环也执行1次,结果符合预期。如:

var b=[1,1]; reDup(b); console.log(b);//[1]

如果有更多的项,那么将符合预期,因此能够正确处理边界条件。

六、栈和队列方法:比较巧妙

事实上,我们还可以有另一种思路:

从前往后依次将数组项取出,若该项尚未取出过,则放入数组尾部,然后去掉该项。若已取出过,则直接抛弃。当完成全部取出操作,原数组已变成去重后的数组。

好处是不用使用循环嵌套,实现的代码如下:

		function reDup(arr){
var temp=[];
var len=arr.length;
for (var i=0; i < len; i++) {
if (temp.indexOf(arr[0])===-1) {
temp.push(arr[0]);
arr.push(arr[0]);
}
arr.shift();
}
}
var array=[1,45,3,1,1,1,4,67,45,45,45];
reDup(array);
console.log(array);//[1, 45, 3, 4, 67]

同样可以正确处理边界条件。

由JS数组去重说起的更多相关文章

  1. js数组去重的4种方法

    js数组去重,老生长谈,今天对其进行一番归纳,总结出来4种方法 贴入代码前 ,先对浏览器Array对象进行支持indexOf和forEach的polyfill Array.prototype.inde ...

  2. JS 数组去重(数组元素是对象的情况)

    js数组去重有经典的 几种方法 但当数组元素是对象时,就不能简单地比较了,需要以某种方式遍历各值再判断是否已出现. 因为: 1.如果是哈希判断法,对象作哈希表的下标,就会自动转换成字符型类型,从而导致 ...

  3. js数组去重常用方法

    js数组去重是面试中经常会碰到的问题,无论是前端还是node.js数组常见的有两种形式,一种是数组各元素均为基本数据类型,常见的为数组字符串格式,形如['a','b','c'];一种是数组各元素不定, ...

  4. js 数组去重小技巧

    js 数组去重小技巧 Intro 今天遇到一个问题,需要对数据进行去重,想看一下有没有什么比较方便的方法,果然有些收获. Question 问题描述: 我有一个这样的数据: [ { "Pro ...

  5. JS数组去重的几种常见方法

    JS数组去重的几种常见方法 一.简单的去重方法 // 最简单数组去重法 /* * 新建一新数组,遍历传入数组,值不在新数组就push进该新数组中 * IE8以下不支持数组的indexOf方法 * */ ...

  6. js数组去重五种方法

    今天来聊一聊JS数组去重的一些方法,包括一些网上看到的和自己总结的,总共5种方法(ES5). 第一种:遍历数组法 这种方法最简单最直观,也最容易理解,代码如下: var arr = [2, 8, 5, ...

  7. js数组去重的方法(转)

    JS数组去重的几种常见方法 一.简单的去重方法 // 最简单数组去重法 /* * 新建一新数组,遍历传入数组,值不在新数组就push进该新数组中 * IE8以下不支持数组的indexOf方法 * */ ...

  8. js 数组去重方法汇总

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  9. js数组去重 javascript版

    //js数组去重 //思路: // 1.放入第一个元素 // 2.放入第n个元素,和第n个之前的元素就行比较,如果有重复,则跳过.没有重复就加入数组中 // 3.返回新的去重后数组 Array.pro ...

  10. js数组去重(多种方法)

    // js数组去重 Array.prototype.fun1 = function(){ var arr = this, result = [], i, len = arr.length; for(i ...

随机推荐

  1. 如何使你的PPT更高调

    PPT是什么? 俗话说的好,PPT就是"屁屁踢"/笑脸. PPT是微软office三件套之一,也就是演示文稿,用于演示(说了给没说一样). PPT的用途 视觉辅助 自动演示 阅读 ...

  2. 家庭记账本app进度之关于tap的相关操作1

    今天还主要学习关于怎样制作微信的先关的tap. 今天的主要成果是已经了解了相关的技术,以及相关的思路.代码经过一个下午的编写,基本接近尾声. 更详细的实验代码,以及相关的知识点将在明天完善后进行发表. ...

  3. Loop Unrolling 循环展开

    在csapp第五章5.2中提到了循环展开(loop unrolling).这里展开一下为什么循环展开可以提升程序的效率. 以书中计算数组和的两段代码为例: 1.未展开: void psum1(floa ...

  4. Linux网络安全篇,进入SELinux的世界(一)

    SELinux 即安全强化的Linux. 一.基本概念 SELinux是通过MAC(强制访问控制,,可以针对特定的进程与特定的文件资源来进行访问权限的控制!也就是说即使你是root,在使用不同的进程时 ...

  5. SIM900A 通过RS232串口进行短信的发送。

    一.基本数据 1.SIM900A模块支持RS232串口和LVTTL串口.保留了232口,在学习或者开发时可以监听51低端单片机和模块指令执行情况,能更快的找出原因,节省开发和学习的时间. 2.此模块供 ...

  6. Android传感器--光照传感器使用

    Android 设备中有许多传感器,其中有一个传感器控制着你屏幕亮度的变化.当你在很暗的地方使用手机,你设备的屏幕会自动调暗,从而保护你眼睛. 起着这样作用,Android是通过一款光照传感器来获取你 ...

  7. TcxLookupComboBox

    1.绑定数据源显示 cxLookupComboBox1.Properties.DropDownAutoSize:=true; //设置下拉列表为自适应宽度 cxLookupComboBox1.Prop ...

  8. 关于 System.IO.File.Exists 需要注意的事项

    各位:   .NET Framework 本省在设计的时候,他对于异常没有完全做到抛出,这样可能会有很多意想不到的问题.   比如 你在asp.net 应用程序中判断文件是否存在,这个文件可能是一个共 ...

  9. Eugene and an array CodeForces - 1333C (思维)

    题目大意:求好数组的个数,所谓好数组 1好数组是原数组的一段连续的子数组,2 好数组不包含元素和为0的子数组. 题解:唉,这个题目把我给些懵了....我一开始的想法求后缀和,保存位置,然后枚举前缀和, ...

  10. Eclipse Hadoop源码阅读环境

    一.解压hadoop src包到workspace目录.为加快下载jar包的速度,在eclipse的maven设置里将配置文件的路径设置正确,然后配置maven的settings.xml: <m ...