我正在尝试用这个目标来解决freeCodeCamp exercise:
编写一个带有两个或更多数组的函数并返回一个新数组 按原始提供的数组的顺序排列唯一值。
换句话说,应包括所有数组中存在的所有值 按照原始顺序,但在最终数组中没有重复。
唯一的数字应按其原始顺序排序,但是 最终数组不应按数字顺序排序。
所以我所做的就是将所有参数连接成一个名为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]);
答案 0 :(得分:4)
看起来你过分复杂了一点;)
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));
我们将问题分为两个步骤:
这部分处理第一步:
[].concat.apply([], arguments)
内置方法someArray.concat(array1, array2 etc)
将给定数组附加到目标。例如,
[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]
如果我们的函数有固定的参数,我们可以直接调用concat
:
function unite(array1, array2, array3) {
var combined = [].concat(array1, array2, array3);
// or
var combined = array1.concat(array2, array3);
但由于我们不知道我们将收到多少args,因此我们必须使用apply
。
someFunction.apply(thisObject, [arg1, arg2, etc])
与
相同 thisObject.someFunction(arg1, arg2, etc)
所以上面一行
var combined = [].concat(array1, array2, array3);
可以写成
var combined = concat.apply([], [array1, array2, array3]);
或只是
var combined = concat.apply([], arguments);
其中arguments
是一个特殊的类数组对象,包含所有函数参数(实际参数)。
实际上,最后两行不起作用,因为concat
不是普通函数,它是Array
个对象的方法,因此是Array.prototype
结构的成员。我们必须告诉JS引擎在哪里找到concat
。我们可以直接使用Array.prototype
:
var combined = Array.prototype.concat.apply([], arguments);
或创建一个新的,不相关的数组对象并从那里拉concat
:
var combined = [].concat.apply([], arguments);
这种原型方法效率稍高(因为我们没有创建虚拟对象),但也更冗长。
无论如何,第一步现在已经完成。为了消除重复,我们使用以下方法:
combined.filter(function(elem, index) {
return combined.indexOf(elem) === index;
})
有关解释和替代方法,请参阅此post。
最后,我们将临时变量(combined
)和链“合并”和“重复数据删除”调用一起删除:
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
使用filter
的第三个参数(“this array”),因为我们不再有变量了。
最后,如果你有兴趣,可以参加一个小练习:
将
combine
和dedupe
写为单独的函数。创建一个函数compose
,它接受两个函数a
和b
并返回一个以相反顺序运行这些函数的新函数,这样compose(a,b)(argument)
将与{b(a(argument))
相同1}}。将unite
的上述定义替换为unite = compose(combine, dedupe)
,并确保其完全相同。
答案 1 :(得分:0)
您也可以尝试以下方法:
var Data = [[1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]]
var UniqueValues = []
for (var i = 0; i < Data.length; i++) {
UniqueValues = [...new Set(UniqueValues.concat(Data[i]))]
}
console.log(UniqueValues)