使用 Reduce 比较多个数组
Comparing Multiple Arrays Using Reduce
对 Javascript 很陌生,我已经在大约一个月的时间里尝试了大约 4 次这个问题,但我仍然无法解决它。
那么问题来了:
构造一个函数交集,比较输入数组和 returns 一个新数组,其中包含在所有输入中找到的元素。奖励:使用减少!
格式为:
function intersection(arrays) {
// Your Code Goes Here
}
测试用例:应该记录 [15, 5]
console.log('Extensions 3 Test: ' + intersection([5, 10, 15, 20], [15, 88, 1, 5, 7]/*, [1, 10, 15, 5, 20]*/));
我目前的解决方案:适用于只有两个项目要比较的情况,但不适用于第三个项目,我可以做到这一点,这样我就可以遍历并将获得的值与下一个数组进行比较,但我没有'认为我走在正确的道路上......另外,我没有使用 reduce 来实现它......而且我不确定我是否应该使用 'arguments.' 任何帮助表示赞赏!非常感谢。
function intersection(arrays) {
array = [];
for (var i = 0; i < arguments.length; i++)
array.push(arguments[i]);
var result = [];
for(var i = 0; i < array.length - 1; i++) {
for(var j = 0; j < array[i].length; j++) {
if (array[i+1].includes(array[i][j]))
result.push(array[i][j]);
}
}
return result;
}
虽然不能直接解决您的问题,但您可以使用开源库来做您想做的事情 underscore.js。
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
您或许可以从已实施的方式中获得灵感。以上是对它们自己的 _.intersection
函数的函数调用,该函数也依赖于其他 underscore.js 函数,如下所示:
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
if (array == null) return [];
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = array.length; i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
};
我想我找到了适合你的功能。
(注意:结果未排序!)
var intersection = function() {
// merge deduped arrays from arguments
var arrays = Array.prototype.reduce.call(arguments, function(carry, array) {
return [].concat(carry, array.filter(function(item, index, origin) {
return origin.indexOf(item) === index;
}));
}, []);
var results = arrays.reduce(function(carry, item, index, arr) {
if(
// just select items, which have more then 1 occurance
arr.filter(function(fItem) {
return fItem === item;
}).length > 1 &&
// ... and which are not already in results
!~carry.indexOf(item)
) {
carry = [].concat(carry,item);
}
return carry;
}, []);
return results;
};
这是一个使用 2 个 reduce 的版本。
第一个只迭代数组一次以创建一个 hashmap 对象来跟踪实例计数,第二个到 return 个值,其中计数与参数数量匹配
function intersection(){
// convert arguments to array of arrays
var arrays = [].slice.call(arguments);
// create an object that tracks counts of instances and is type specific
// so numbers and strings would not be counted as same
var counts= arrays.reduce(function(a,c){
// iterate sub array and count element instances
c.forEach(function(val){
var propName = typeof val + '|' + val;
// if array value not previously encountered add a new property
a[propName] = a[propName] || {count:0, value: val};
// increment count for that property
a[propName].count++;
});
return a;
},{});
// iterate above object to return array of values where count matches total arrays length
return Object.keys(counts).reduce(function(resArr, propName){
if(counts[propName].count === arrays.length){
resArr.push(counts[propName].value);
}
return resArr;
},[]);
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]))
可以使用一些微调来确保有足够的参数并且它们都是数组
虽然,正如一些建议所说,你可以使用 underscore, lodash, or my personal favorite, Ramda(免责声明:我是作者之一),这个函数应该足够简单,你甚至不会考虑为它建一个图书馆。这是一个简单的版本:
const intersection = (xs, ys) => xs.filter(x => ys.indexOf(x) > -1);
intersection([5, 10, 15, 20, 3], [15, 88, 3, 1, 5, 7]); //=> [5, 15, 3]
const intersectAll = (...xss) => xss.reduce(intersection);
intersectAll([5, 10, 15, 20, 3], [15, 88, 3, 1, 5, 7], [1, 10, 15, 5, 20]); //=> [5, 15]
我认为这就是您所需要的,至少只要您只担心 reference/primitive 平等并且不需要考虑您想知道 {x: 1}
和 {x: 1}
是相同的,即使它们不是相同的引用。如果确实需要,可以查看 Ramda 的 intersection
函数。
请注意,如果 includes
是 better supported,我会推荐这个版本,因为它读起来更好:
const intersection = (xs, ys) => xs.filter(x => ys.includes(x));
此外,如果您不需要二元函数,您可以通过组合以上两个来制作它的可变版本:
const intersection = (...xss) => xss.reduce((xs, ys) => xs.filter(x => ys.indexOf(x) > -1));
以下是我使用 vanilla javascript 和一个 reduce 调用的结果。
function intersection(){
var arrays = [].slice.call(arguments);
var first = arrays[0];
var rest = arrays.slice(1);
return first.reduce(function(all, item, index){
var push = rest.every(function(subArray){
return subArray.indexOf(item) > -1;
});
if(push){
all.push(item);
}
return all;
},[])
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
这是一个使用reduce的解决方案,空数组作为交集作为初始值传入。
迭代数字并检查每个数字是否出现在子数组之一中。
如果不是,请将布尔值 isPresentInAll 设置为 false。
如果它确实出现在所有三个中并且它还没有出现在
交集数组,然后推送到交集数组。
function intersection(arrayOfArrays) {
return arrayOfArrays.reduce(function(intersection, subArray) {
subArray.forEach(function(number) {
var isPresentInAll = true;
for (var i = 0; i < arrayOfArrays.length; i++) {
if (arrayOfArrays[i].indexOf(number) === -1) {
isPresentInAll = false;
}
}
if (isPresentInAll === true && intersection.indexOf(number) === -1) {
intersection.push(number);
}
});
return intersection;
}, []);
}
function intersection(arrays) {
let common = arrays.reduce(function(accumulator, currentValue) {
return accumulator.filter(function(x){
return currentValue.indexOf(x) > -1;
})
})
return common;
}
为了优化您无法处理超过 2 个子数组且未使用 reduce 的答案,这里是适用于您传入的许多子数组的代码。
function intersection(arr1, arr2, arr3){
let ans = arr1[0]; // ans = [5,10,15,20]
for(let i = 0; i < ans.length; i++){ // i = 0...3
for(let j = 1; j < arr1.length; j++){ // j = 1...2
if(!(arr1[j].includes(ans[i]))){ // if the new subarray doesn't include an element in the ans
ans.splice(i, 1); // delete the element from ans
}
}
}
return ans;
}
const arr1 = [5, 10, 15, 20];
const arr2 = [15, 88, 1, 5, 7];
const arr3 = [1, 10, 15, 5, 20];
console.log(intersection([arr1, arr2, arr3])); // should log: [5, 15]
也许有人会觉得有用。
作为函数的参数,你可以给出任意数量的任意长度的数组,而且函数是紧凑的,我认为 ;)
const findSimilar = (...arrays) => {
return arrays.reduce((includ, current) =>
Array.from(new Set(includ.filter((a) => current.includes(a))))
);
};
console.log(
findSimilar([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20])
);
它是如何工作的:
好的,首先你将 rest parameters(...arrays) 作为函数的参数,所以你有
数组 = [ [5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20] ]
然后在 reduce 的第一次迭代中我们有
包括 = [5, 10, 15, 20] 和当前 = [15, 88, 1, 5, 7]
在这两个上我们使用 filter, what give us [5,15], i use Set to make shure there is no repetition and make array back (Array.from()),它作为 "includ" 传递给 reduce 的下一次迭代,在下一次迭代中我们有
incude = [5,15] 和 current = [1, 10, 15, 5, 20] 等等...
我们甚至可以这样使用
let result = [
[5, 10, 15, 20],
[15, 88, 1, 5, 7],
[1, 10, 15, 5, 20]
].reduce((includ, current) =>
Array.from(new Set(includ.filter((a) => current.includes(a))))
);
console.log(result);
对 Javascript 很陌生,我已经在大约一个月的时间里尝试了大约 4 次这个问题,但我仍然无法解决它。
那么问题来了: 构造一个函数交集,比较输入数组和 returns 一个新数组,其中包含在所有输入中找到的元素。奖励:使用减少!
格式为:
function intersection(arrays) {
// Your Code Goes Here
}
测试用例:应该记录 [15, 5]
console.log('Extensions 3 Test: ' + intersection([5, 10, 15, 20], [15, 88, 1, 5, 7]/*, [1, 10, 15, 5, 20]*/));
我目前的解决方案:适用于只有两个项目要比较的情况,但不适用于第三个项目,我可以做到这一点,这样我就可以遍历并将获得的值与下一个数组进行比较,但我没有'认为我走在正确的道路上......另外,我没有使用 reduce 来实现它......而且我不确定我是否应该使用 'arguments.' 任何帮助表示赞赏!非常感谢。
function intersection(arrays) {
array = [];
for (var i = 0; i < arguments.length; i++)
array.push(arguments[i]);
var result = [];
for(var i = 0; i < array.length - 1; i++) {
for(var j = 0; j < array[i].length; j++) {
if (array[i+1].includes(array[i][j]))
result.push(array[i][j]);
}
}
return result;
}
虽然不能直接解决您的问题,但您可以使用开源库来做您想做的事情 underscore.js。
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
您或许可以从已实施的方式中获得灵感。以上是对它们自己的 _.intersection
函数的函数调用,该函数也依赖于其他 underscore.js 函数,如下所示:
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
if (array == null) return [];
var result = [];
var argsLength = arguments.length;
for (var i = 0, length = array.length; i < length; i++) {
var item = array[i];
if (_.contains(result, item)) continue;
for (var j = 1; j < argsLength; j++) {
if (!_.contains(arguments[j], item)) break;
}
if (j === argsLength) result.push(item);
}
return result;
};
我想我找到了适合你的功能。 (注意:结果未排序!)
var intersection = function() {
// merge deduped arrays from arguments
var arrays = Array.prototype.reduce.call(arguments, function(carry, array) {
return [].concat(carry, array.filter(function(item, index, origin) {
return origin.indexOf(item) === index;
}));
}, []);
var results = arrays.reduce(function(carry, item, index, arr) {
if(
// just select items, which have more then 1 occurance
arr.filter(function(fItem) {
return fItem === item;
}).length > 1 &&
// ... and which are not already in results
!~carry.indexOf(item)
) {
carry = [].concat(carry,item);
}
return carry;
}, []);
return results;
};
这是一个使用 2 个 reduce 的版本。
第一个只迭代数组一次以创建一个 hashmap 对象来跟踪实例计数,第二个到 return 个值,其中计数与参数数量匹配
function intersection(){
// convert arguments to array of arrays
var arrays = [].slice.call(arguments);
// create an object that tracks counts of instances and is type specific
// so numbers and strings would not be counted as same
var counts= arrays.reduce(function(a,c){
// iterate sub array and count element instances
c.forEach(function(val){
var propName = typeof val + '|' + val;
// if array value not previously encountered add a new property
a[propName] = a[propName] || {count:0, value: val};
// increment count for that property
a[propName].count++;
});
return a;
},{});
// iterate above object to return array of values where count matches total arrays length
return Object.keys(counts).reduce(function(resArr, propName){
if(counts[propName].count === arrays.length){
resArr.push(counts[propName].value);
}
return resArr;
},[]);
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]))
可以使用一些微调来确保有足够的参数并且它们都是数组
虽然,正如一些建议所说,你可以使用 underscore, lodash, or my personal favorite, Ramda(免责声明:我是作者之一),这个函数应该足够简单,你甚至不会考虑为它建一个图书馆。这是一个简单的版本:
const intersection = (xs, ys) => xs.filter(x => ys.indexOf(x) > -1);
intersection([5, 10, 15, 20, 3], [15, 88, 3, 1, 5, 7]); //=> [5, 15, 3]
const intersectAll = (...xss) => xss.reduce(intersection);
intersectAll([5, 10, 15, 20, 3], [15, 88, 3, 1, 5, 7], [1, 10, 15, 5, 20]); //=> [5, 15]
我认为这就是您所需要的,至少只要您只担心 reference/primitive 平等并且不需要考虑您想知道 {x: 1}
和 {x: 1}
是相同的,即使它们不是相同的引用。如果确实需要,可以查看 Ramda 的 intersection
函数。
请注意,如果 includes
是 better supported,我会推荐这个版本,因为它读起来更好:
const intersection = (xs, ys) => xs.filter(x => ys.includes(x));
此外,如果您不需要二元函数,您可以通过组合以上两个来制作它的可变版本:
const intersection = (...xss) => xss.reduce((xs, ys) => xs.filter(x => ys.indexOf(x) > -1));
以下是我使用 vanilla javascript 和一个 reduce 调用的结果。
function intersection(){
var arrays = [].slice.call(arguments);
var first = arrays[0];
var rest = arrays.slice(1);
return first.reduce(function(all, item, index){
var push = rest.every(function(subArray){
return subArray.indexOf(item) > -1;
});
if(push){
all.push(item);
}
return all;
},[])
}
console.log(intersection([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20]));
这是一个使用reduce的解决方案,空数组作为交集作为初始值传入。
迭代数字并检查每个数字是否出现在子数组之一中。
如果不是,请将布尔值 isPresentInAll 设置为 false。
如果它确实出现在所有三个中并且它还没有出现在 交集数组,然后推送到交集数组。
function intersection(arrayOfArrays) {
return arrayOfArrays.reduce(function(intersection, subArray) {
subArray.forEach(function(number) {
var isPresentInAll = true;
for (var i = 0; i < arrayOfArrays.length; i++) {
if (arrayOfArrays[i].indexOf(number) === -1) {
isPresentInAll = false;
}
}
if (isPresentInAll === true && intersection.indexOf(number) === -1) {
intersection.push(number);
}
});
return intersection;
}, []);
}
function intersection(arrays) {
let common = arrays.reduce(function(accumulator, currentValue) {
return accumulator.filter(function(x){
return currentValue.indexOf(x) > -1;
})
})
return common;
}
为了优化您无法处理超过 2 个子数组且未使用 reduce 的答案,这里是适用于您传入的许多子数组的代码。
function intersection(arr1, arr2, arr3){
let ans = arr1[0]; // ans = [5,10,15,20]
for(let i = 0; i < ans.length; i++){ // i = 0...3
for(let j = 1; j < arr1.length; j++){ // j = 1...2
if(!(arr1[j].includes(ans[i]))){ // if the new subarray doesn't include an element in the ans
ans.splice(i, 1); // delete the element from ans
}
}
}
return ans;
}
const arr1 = [5, 10, 15, 20];
const arr2 = [15, 88, 1, 5, 7];
const arr3 = [1, 10, 15, 5, 20];
console.log(intersection([arr1, arr2, arr3])); // should log: [5, 15]
也许有人会觉得有用。
作为函数的参数,你可以给出任意数量的任意长度的数组,而且函数是紧凑的,我认为 ;)
const findSimilar = (...arrays) => {
return arrays.reduce((includ, current) =>
Array.from(new Set(includ.filter((a) => current.includes(a))))
);
};
console.log(
findSimilar([5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20])
);
它是如何工作的:
好的,首先你将 rest parameters(...arrays) 作为函数的参数,所以你有
数组 = [ [5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20] ]
然后在 reduce 的第一次迭代中我们有
包括 = [5, 10, 15, 20] 和当前 = [15, 88, 1, 5, 7]
在这两个上我们使用 filter, what give us [5,15], i use Set to make shure there is no repetition and make array back (Array.from()),它作为 "includ" 传递给 reduce 的下一次迭代,在下一次迭代中我们有
incude = [5,15] 和 current = [1, 10, 15, 5, 20] 等等...
我们甚至可以这样使用
let result = [
[5, 10, 15, 20],
[15, 88, 1, 5, 7],
[1, 10, 15, 5, 20]
].reduce((includ, current) =>
Array.from(new Set(includ.filter((a) => current.includes(a))))
);
console.log(result);