使用JavaScript中的数组.reduce方法去除重复项。

5

我是javascript的新手,从网络教程中自学时遇到一些困难。请帮助我解决下面的问题。

问题:

编写一个函数,它接受两个或更多数组,并返回一个新数组,其中包含原始提供的数组的唯一值,按其原始顺序排序。

换句话说,所有数组中存在的值都应以其原始顺序包含在内,但是最终数组中不应有重复项。

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

只使用Array.reduce来解决!您的解决方案应如下所示:

function unite(arr1, arr2, arr3) {
  return arr1;
}

unite([1, 2, 3], [5, 2, 1, 4], [2, 1]);

我不明白如何在这里使用reduce。所有的互联网例子与这个相比都太容易了。
以下是两个相关链接: https://www.airpair.com/javascript/javascript-array-reduce http://adripofjavascript.com/blog/drips/boiling-down-arrays-with-array-reduce.html
function arrayDiff(resultArray, element){
    var idx = anotherArray.indexOf(element);
    if(idx != -1){
        resultArray.push(element);
        return resultArray;
    }
}

function unite(arr1, arr2, arr3) {
    var arr = [];
    var r1 = arr1.reduce(arrayDiff);
    var r2 = arr2.reduce(arrayDiff);
    var r3 = arr3.reduce(arrayDiff);
    arr.concat(r1).concat(r2).concat(r3);
    return arr;
}


r = unite([1, 2, 3], [5, 2, 1, 4], [2, 1]);
console.log(r);

错误:ReferenceError: anotherArray未定义


那是因为“anotherArray”未被定义。这个变量应该指代什么? - zerkms
是的,anotherArray未定义。你期望它是什么? - Bergi
@Bergi - 我刚刚在这里看到了一个例子 - var sum = [1, 2, 3].reduce( function(total, num){ return total + num }, 0);。看起来total是结果变量。所以,我按照那个例子,把anotherArray作为我的结果变量。这很令人困惑。 - stack1
如果您再次查看您提供的示例,您会注意到total是第一个参数。 - zerkms
@Bergi 是的,我已经意识到了并决定完全删除它。 - zerkms
5个回答

7
为了处理多个数组参数,您可以使用 arguments。这样,您的函数可以接受N个参数,更加通用。
然后,您可以扁平化所有的数组参数,并开始减少数据。当您减少我们的数组时,您将通过排除冗余数据来创建一个新的数组。因此,您将从一个数组开始,并通过减少过程填充它。
  function unite(){
    //Flat array arguments, then process to reduce data
    return [].concat.apply([], arguments).reduce(function(result, current){
      //If my result array doesn't get current element
      return result.indexOf(current) === -1
      //concat current element to result and return it
      ? result.concat(current)
      //Otherwise, just return actual result array
      : result;
    }, []);
  }

  var array = unite([1,2], [1,6,2,3], [4,5]);

  console.log(array);
  //[1,2,6,3,4,5]

编辑于06/02/2017:

现在,您可以使用展开运算符来处理多个参数,例如通过解构赋值。 此外,我们可以通过使用具有按位运算符~indexOf()操作来提高性能。

function unite(...data) {
  return [].concat.apply([], data).reduce((result, current) => {
    return ~result.indexOf(current)
    ? result
    : result.concat(current)
  }, []);
}

console.log(unite([1,2,3], [1, 4, 4, 5, 6]));

我基本上写了完全相同的解决方案,但我会给你点赞 :) - Peter

1
我想你想要检查element是否已经在resultArray中,而不是在另一个anotherArray中。这样,它可能会有点起作用:
function arrayDiff(resultArray, element){
    var idx = resultArray.indexOf(element);
    if (idx == -1) { // add only when not already found in the result array
        resultArray.push(element);
    }
    return resultArray; // always return the resultArray even if we didn't add to it
}

function unite(arr1, arr2, arr3) {
    var r0 = [];
    var r1 = arr1.reduce(arrayDiff, r0); // supply some start accumulator argument
    var r2 = arr2.reduce(arrayDiff, r1); // and pass the results through so that
    var r3 = arr3.reduce(arrayDiff, r2); // duplicates are filtered amongst all arrays
    return r3;
}

@stack1 顺便说一下,这个解决方案并没有解决你的原始任务(但这很好,现在你有机会改进它)。 - zerkms
@stack1:没错,就是那个。我们从空数组开始,然后对第一个 arr1 进行归约操作,以获取其中所有不重复的值,接着我们使用该结果作为起始值对 arr2 进行归约操作,以添加那些尚未存在的值,等等。 - Bergi
@zerkms:你是不是想说 !=?不是故意的 :-) - Bergi
@Bergi 不是的 ;-) "编写一个函数,该函数接受两个或更多数组" - zerkms
@zerkms:啊,是的,对参数进行缩减...我想知道为什么它不能与无或单个数组一起使用。 - Bergi
显示剩余2条评论

0

我的解决方案

function unique(array) {
  return array.reduce(function(results,currentItem){ 
    //using array include
    return results.includes(currentItem)? results: [...results,currentItem];

    //using array find
    //return results.find(function(result){return currentItem===result})?results:[...results,currentItem];
  },[]);
}

0

这是我的解决方案,更加简洁/短小:

function uniteUnique(arr) {
  var args = Array.from(arguments);
  var test = [];

  for ( var i = 0; i < args.length; i++ ) {
    for (var j = 0; j < args[i].length; j++ ) {
      if ( test.indexOf(args[i][j]) == -1 ) {      
          test.push(args[i][j]);
      }
    }
  }

  return test;
}

uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);

0

Reduce非常强大,但可能会令人困惑。请确保始终初始化累加器并从reducer函数返回累加器。

    let originalArray = [[1,2], [1,6,2,3], [4,5]];

    let arrayFiltered = originalArray.reduce((acc, arrayvalue) => {
      arrayvalue.forEach(item => {
        if(acc.indexOf(item) === -1) {
        acc.push(item);
      }})
      return acc;
    }, []);

  console.log(arrayFiltered); //[1, 2, 6, 3, 4, 5]

在foreach循环内检查每个数字的值,如果它存在于累加器中,则不执行任何操作,否则将其推入累加器中。

https://jsfiddle.net/bradrice/bq84wry2/1/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接