在多个数组中查找唯一值

Mih*_*šič 1 javascript arrays for-loop

我正在尝试解决具有以下目标的freeCodeCamp练习

编写一个函数,该函数接受两个或多个数组,并按原始提供的数组的顺序返回一个唯一值的新数组。

换句话说,所有数组中出现的所有值都应按其原始顺序包括在内,但最终数组中不得重复。

唯一数字应按其原始顺序排序,但最终数组不应按数字顺序排序。

因此,我要做的是将所有参数连接到一个名为的数组中everything。然后,我在数组中搜索重复项,然后在参数中搜索这些重复项并将.splice()其删除。

到目前为止,一切都按预期工作,但是最后一个参数的最后一个数字没有被删除,我无法真正弄清楚原因。

有人可以指出我做错了吗?请记住,我正在尝试学习,因此显而易见的事情对我而言可能并不明显,需要指出。提前致谢。

function unite(arr1, arr2, arr3) {
  var everything = [];
  //concat all arrays except the first one
  for(var x = 0; x < arguments.length; x++) {
    for(var y = 0; y < arguments[x].length; y++) {
      everything.push(arguments[x][y]);
    }
  }
  
  //function that returns duplicates
  function returnUnique(arr) {
    return arr.reduce(function(dupes, val, i) {
      if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
        dupes.push(val);
      }
      return dupes;
    }, []);
  }
  
  //return duplicates
  var dupes = returnUnique(everything);
  
  //remove duplicates from all arguments except the first one
  for(var n = 1; n < arguments.length; n++) {
    for(var m = 0; m < dupes.length; m++) {
      if(arguments[n].hasOwnProperty(dupes[m])) {
        arguments[n].splice(arguments[n].indexOf(dupes[m]), 1);
      }
    }
  }
  
  //return concatenation of the reduced arguments
  return arr1.concat(arr2).concat(arr3);
  
}  

//this returns [1, 3, 2, 5, 4, 2]
unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);
Run Code Online (Sandbox Code Playgroud)

geo*_*org 5

看起来您有点复杂了;)

function unite() {
    return [].concat.apply([], arguments).filter(function(elem, index, self) {
        return self.indexOf(elem) === index;
    });
}


res = unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]);
document.write('<pre>'+JSON.stringify(res));
Run Code Online (Sandbox Code Playgroud)

说明

我们将问题分为两个步骤:

  • 将参数合并为一个大数组
  • 从这个大数组中删除非唯一元素

此部分处理第一步:

[].concat.apply([], arguments)
Run Code Online (Sandbox Code Playgroud)

内置方法someArray.concat(array1, array2 etc)将给定数组附加到目标。例如,

[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]
Run Code Online (Sandbox Code Playgroud)

如果我们的函数具有固定的参数,则可以concat直接调用:

function unite(array1, array2, array3) {
    var combined = [].concat(array1, array2, array3);
    // or
    var combined = array1.concat(array2, array3);
Run Code Online (Sandbox Code Playgroud)

但由于我们不知道要接收多少个args,因此必须使用apply

 someFunction.apply(thisObject, [arg1, arg2, etc])
Run Code Online (Sandbox Code Playgroud)

是相同的

 thisObject.someFunction(arg1, arg2, etc)
Run Code Online (Sandbox Code Playgroud)

所以上面的线

 var combined = [].concat(array1, array2, array3);
Run Code Online (Sandbox Code Playgroud)

可以写成

 var combined = concat.apply([], [array1, array2, array3]);
Run Code Online (Sandbox Code Playgroud)

或简单地

 var combined = concat.apply([], arguments);
Run Code Online (Sandbox Code Playgroud)

其中arguments是一个特殊的类似数组的对象,其中包含所有函数参数(实际参数)。

实际上,最后两行不起作用,因为concat它不是简单的函数,而是Array对象的方法,因此也是Array.prototype结构的成员。我们必须告诉JS引擎在哪里可以找到concat。我们可以Array.prototype直接使用:

 var combined = Array.prototype.concat.apply([], arguments);
Run Code Online (Sandbox Code Playgroud)

或创建一个新的,不相关的数组对象并concat从此处拉出:

 var combined = [].concat.apply([], arguments);
Run Code Online (Sandbox Code Playgroud)

这种原型方法效率稍高(因为我们没有创建虚拟对象),但是也比较冗长。

无论如何,第一步已经完成。为了消除重复,我们使用以下方法:

 combined.filter(function(elem, index) {
     return combined.indexOf(elem) === index;
 })
Run Code Online (Sandbox Code Playgroud)

有关说明和替代方法,请参阅此文章

最后,我们摆脱了临时变量(combined),并将“ combine”和“ dedupe”调用链链接在一起:

return [].concat.apply([], arguments).filter(function(elem, index, self) {
    return self.indexOf(elem) === index;
});
Run Code Online (Sandbox Code Playgroud)

使用的第三个参数(“此数组”)是filter因为我们没有变量了。

很简单,不是吗?;)让我们知道您是否有任何疑问。

最后,如果您有兴趣,可以做一个小练习:

编写combinededupe作为单独的函数。创建一个compose具有两个函数ab返回一个新函数的函数,该新函数以相反的顺序运行这些函数,因此compose(a,b)(argument)与相同b(a(argument))。替换的上述定义uniteunite = compose(combine, dedupe),并确保它的工作原理完全一样。