JavaScript算法练习:从数组中寻找元素并删除元素

发布于 大漠

今天的任务中创建一个destroyer()函数,其功能是对所给的数组根据参数删除这些元素。也就是说给destroyer()传入一个参数arr,而且这个参数是类似这样的[1,2,3,4,5,2,3,1,3],1,3,要做的事情就是从数组[1,2,3,4,5,2,3,1,3]删除所有的13元素。

实现思路

知道要完成的任务之后,要有一个实现思路,其简单的可以概括为:

  • 通过arguments对象将所有参数包装成一个数组args
  • 通过JavaScript的一些方法将arr参数移除,也就是需要删除的参数
  • 通过Array.indexOf()arr除外的args数组做为过滤的条件
  • 通过filter()方法创建过滤条件,将arr中符合filter()条件的元素删除,当然除了通过filter()之外,还可以使用JavaScript中的for循环
  • 返回最后的arr

将涉及到的JavaScript方法

有思路了,就好办了,这里简单罗列一些将要用到的JavaScript方法:

上面的知识点是后面所有解决方案都将会涉及到的。为了更好的理解后面的解决方案,简单的回忆一下这几个知识点。

arguments是一个类数组对象。代表传给一个function的参数列表。它是函数内部的本地变量,已不再是函数的属必了。可以在函数内部通过使用arguments对象来获取函数的所有参数。

特别强调了,arguments对象仅在函数内部有效,在函数外部调用arguments对象会出现一个错误。来看一个简单的示列:

function destroyer (arr) {
    // 将所传的参数转换成数组args
    var args = arguments;
    console.log(args); //[[1,2,1,3,2,1,3,4,2,6],1,2]

    for (var i = 0, len = arguments.length; i < len; i++) {
        console.log(arguments[i]);
        /*
         * i = 0 => arguments[0] = [1,2,1,3,2,1,3,4,2,6]
         * i = 1 => arguments[1] = 1
         * i = 2 => arguments[2] = 2
         */
    }
}

destroyer([1,2,1,3,2,1,3,4,2,6],1,2);

从上面的示例,可以知道,通过arguments[0]可以获取到的数组arr,也就是目标数组。同时通过JavaScript的push()splice()或者shift()之类的方法来删除args数组中的第一个元素,从而得到需要从arr中移除的参数,其也是一个数组,比如说将其称为removeArgs

其实除了这些方法之外,可以通过arguments带一个参数,就可以直接得到需要移除的参数removeArgs数组:

removeArgs = Array.prototype.slice.call(arguments, 1); // [1, 2]

这样一来,就得到了目标数组,比如说将其称之为newArray和需要移除的数组removeArgs。那么就可以Array.prototype.indexOf()获取removeArgs中的索引值index,如果其等于-1,就表示元素不在数组removeArgs中,否则将返回对应的索引值:

[1,2].indexOf(1) = 0 

然后使用===或者!==来做比较

removeArgs.indexOf(value) === -1;

如果其值不为-1将返回false

[1,2].indexOf(1) = 0  => false
[1,2].indexOf(2) = 1  => false

而我们的目标就是从newArray中移除removeArgs中有相同的元素。比如说:

newArray = [1,2,1,3,2,1,3,4,2,6]
removeArgs= [1,2]

也就是说从[1,2,1,3,2,1,3,4,2,6]移除所有的12,最后得到的数组arr

arr = [3, 3, 4, 6]

要从一个数组中过滤掉对应的参数,大家肯定会想到filter()方法,如果其callback函数返回的值为false时,就会从数组中删除这个值,从而将符合条件的元素组成一个新的数组。也就是我们最终需要的数组arr

解决方案

要实现这个功能,实现方案非常的多,下面罗列一些搜集来的解决方案,以供大家学习和参考:

方法1

function destroyer(arr) {
    // 获取目标数组
    var newArray = arguments[0]; // [1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
    // 声明一个空数组,用来存储需要从`newArray`中删除的元素
    var removeArgs = [];

    for (var i = 1, len = arguments.length; i < len; i++) {
        removeArgs.push(arguments[i]);
        /*
         *  遍历次数  i  len   i < len  i++  arguments[i]  removeArgs
         *  1st     1    3     yes      2     1            [1]
         *  2nd     2    3     yes      3     2            [1,2]
         *  3rd     3    3     no
         *  end loop
         *  
         */
    }

    // 声明filter()方法的callback函数

    function isFalse (value) {
          return removeArgs.indexOf(value) === -1;
      	
      	/*
         *  removeArgs = [1,2]
         *  removeArgs.indexOf(value) = ?  removeArgs.indexOf(value) === -1
         *  [1,2].indexOf(1) = 0              false
         *  [1,2].indexOf(2) = 1              false
         *
         */
    }
    
    return newArray.filter(isFalse);// newArray中删除1,2
}

在Chrome中运行后:

destroyer([1,2,1,3,2,1,3,4,2,6],1,2); // [3, 3, 4, 6]

方法2

function destroyer(arr) {
    var newArray = arguments[0]; //[1,2,1,3,2,1,3,4,2,6]
    var removeArgs = [];

    for (var i = 1, len = arguments.length; i < len; i++) {
        removeArgs.push(arguments[i]);
        /*
         *  遍历次数  i  len   i < len  i++  arguments[i]  removeArgs
         *  1st     1    3     yes      2     1            [1]
         *  2nd     2    3     yes      3     2            [1,2]
         *  3rd     3    3     no
         *  end loop
         *  
         */
    }

    function isFalse (value) {
      for (var j = 0; j < removeArgs.length; j++) {
        if (removeArgs[j] == value) {
          return false;
        }
        /*
         * removeArgs = [1,2]
         * 遍历次数   j = ?  j < removeArgs.length  j++  removeArgs[j]   value  removeArgs[j] == value
         * 1st        0     yes                    1     1               1       false
         * 2nd        1     yes                    2     2               2       false
         * 3rd        2     no
         * end loop
         * 
         */
      }
      return true;
    }

    return newArray.filter(isFalse); // 从newArray数组中删除1,2
}

方法3

function destroyer(arr) {
    var args = Array.prototype.slice.call(arguments); // [[1,2,1,3,2,1,3,4,2,6],1,2]
    args.splice(0, 1); // 从数组中args删除第一个元素[1,2,1,3,2,1,3,4,2,6], args数组变成[1,2]
    
    // arr = [1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
    return arr.filter(function(value) {
        return args.indexOf(value) === -1;
    });
}

方法4

function destroyer(arr) {
    var removeArgs = Array.prototype.slice.call(arguments, 1); // [1, 2]

    // arr = [1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
    return arr.filter(function(value) {
        return removeArgs.indexOf(value) < 0;
    });
}

方法5

function destroyer(arr) {
    var args = arguments;//[[1, 2, 1, 3, 2, 1, 3, 4, 2, 6], 1, 2]

    function isFalse (value) {
      for (var i = 1, len = args.length; i < len; i++){
        if (args[i] == value) {
          return false;
        }
      }
      return true;
    }
    // arr = [1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
    return arr.filter(isFalse);
}

方法6

function destroyer(arr) {
    var args = Array.prototype.slice.call(arguments); //[[1, 2, 1, 3, 2, 1, 3, 4, 2, 6], 1, 2]
    var newArray = args.shift(); //[1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
    // 这里args = [1,2]
    
    function isFalse (a) {
      return args.every( function (b) {
        return a !== b;
      });
    }

    return newArray.filter(isFalse);
}

方法7

function destroyer(arr) {
    var removeArgs = Array.prototype.slice.call(arguments, 1);// [1,2]

    function isFalse (a) {
      return !removeArgs.some (function (b) {
        return a === b;
      })
    }

    return arr.filter(isFalse);
}

方法8

function destroyer(arr) {
    var removeArgs = Array.prototype.slice.call(arguments, 1); // [1,2]
    removeArgs.forEach(function(value) {
        // arr = [1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
        var index = arr.indexOf(value);
        while (index > -1) {
            arr.splice(index, 1);
            index = arr.indexOf(value);
        }
    });
    return arr;
}

方法9

function destroyer(arr) {
    // arguments = [[1, 2, 1, 3, 2, 1, 3, 4, 2, 6],1,2]
    for (var i = 1; i < arguments.length; i++) {
        // arr = [1, 2, 1, 3, 2, 1, 3, 4, 2, 6]
        for (var j = 0; j < arr.length; j++) {
            if (arguments[i] == arr[j]) {
                arr.splice(j, 1);
                --j;
            }
        }
    }
    return arr;
}

也可以换成这样的方式:

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

方法10

除了上述方法之外,还可以使用ES6中的一些方法:

比如:

function destroyer(arr) {
    var removeArgs = new Set(Array.prototype.slice.call(arguments, 1)); //Set {1, 2}
    
    function isFalse (value) {
      return !removeArgs.has(value);
    }

    return arr.filter(isFalse);
}

也可以将上述方法改成:

function destroyer(arr, ...items) {
  	var removeArgs = new Set(items); // Set {1, 2}
  
  	function isFalse (value) {
    	return !removeArgs.has(value);
  	}

  	return arr.filter(isFalse);
}

总结

上面使用了十种方法实现了我们要完成的任务。不管什么使用什么方法,都有自己的优势和弊端。我想说的是,只要大家掌握了基础,对这JavaScript这些基础知识了解通透,我们就可以从不同的角度和使用不同的方法达到我们的目标,或者完成我们所要完成的任务。当然如果你经验十足,您能找到最简单,最高效的方案。如果您有更好的解决方案,欢迎在下面的评论中与我们分享。最后再给大家提供一个视频:

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/javascript/seek-and-destroy-in-javascript.htmlAir Max 1 Ultra Flyknit