繁体   English   中英

使用 Reduce 比较多个数组

[英]Comparing Multiple Arrays Using Reduce

Javascript 非常新,我在大约一个月的时间里已经尝试了这个问题大约 4 次,但我仍然无法解决它。

所以这里的问题是:构造一个函数交集,比较输入数组并返回一个包含在所有输入中找到的元素的新数组。 奖励:使用减少!

格式为:

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 来实现它......而且我不确定我是否应该使用“参数”。 任何帮助表示赞赏! 非常感谢。

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;
}

虽然几个建议说,你可以使用下划线lodash ,或者我个人的最爱, 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]

我认为这就是你所需要的,至少只要你只担心引用/原始相等并且不需要考虑你想知道{x: 1}{x: 1}是相同的,即使它们不是相同的参考。 如果确实需要,可以查看 Ramda 的intersection函数。

请注意,如果includes 更好的支持,我会推荐这个版本,因为它读起来更好:

const intersection = (xs, ys) => xs.filter(x => ys.includes(x));

此外,如果您不需要二元函数,您可以通过组合以上两个来制作它的可变参数版本:

const intersection = (...xss) => xss.reduce((xs, ys) => xs.filter(x => ys.indexOf(x) > -1));

也许有人会发现它很有用。

作为函数的参数,您可以提供任意数量的任意长度的数组,并且该函数是紧凑的,我认为 ;)

 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]) );

以及它是如何工作的:
好的,首先你将其余参数(...数组)作为函数的参数,所以你有
数组 = [ [5, 10, 15, 20], [15, 88, 1, 5, 7], [1, 10, 15, 5, 20] ]
然后在减少的第一次迭代中我们有
包括 = [5, 10, 15, 20] 和当前 = [15, 88, 1, 5, 7]
在这两个上我们使用filter ,什么给了我们 [5,15],我使用Set使 shure 没有重复并使数组返回( 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);

虽然不能直接解决您的问题,但您可以使用开源库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;
  };

这是使用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;
  }, []);
}

我想我得到了适合你的功能。 (注意:结果未排序!)

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 减少的版本。

第一个只迭代数组一次以创建一个 hashmap 对象来跟踪实例计数,第二个返回计数与参数数量匹配的值

 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]))

可以使用一些微调来确保有足够的参数并且它们都是数组

这是我想出的使用 vanilla javascript 和一个减少调用的方法。

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]));
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]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM