最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Finding unique values in multiple arrays - Stack Overflow

programmeradmin0浏览0评论

I'm trying to solve a freeCodeCamp exercise with this goal:

Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays.

In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array.

The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order.

So what I do is concatenate all the arguments into a single array called everything. I then search the array for duplicates, then search the arguments for these duplicates and .splice() them out.

So far everything works as expected, but the last number of the last argument does not get removed and I can't really figure out why.

Can anybody please point out what I'm doing wrong? Please keep in mind that I'm trying to learn, so obvious things probably won't be obvious to me and need to be pointed out. Thanks in advance.

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

I'm trying to solve a freeCodeCamp exercise with this goal:

Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays.

In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array.

The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order.

So what I do is concatenate all the arguments into a single array called everything. I then search the array for duplicates, then search the arguments for these duplicates and .splice() them out.

So far everything works as expected, but the last number of the last argument does not get removed and I can't really figure out why.

Can anybody please point out what I'm doing wrong? Please keep in mind that I'm trying to learn, so obvious things probably won't be obvious to me and need to be pointed out. Thanks in advance.

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

Share Improve this question asked Feb 1, 2016 at 18:00 Miha ŠušteršičMiha Šušteršič 10.1k27 gold badges97 silver badges175 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 9

Looks like you overplicated it a bit ;)

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

Explanations

We split the problem into two steps:

  • bine arguments into one big array
  • remove non-unique elements from this big array

This part handles the first step:

[].concat.apply([], arguments)

The built-in method someArray.concat(array1, array2 etc) appends given arrays to the target. For example,

[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]

If our function had fixed arguments, we could call concat directly:

function unite(array1, array2, array3) {
    var bined = [].concat(array1, array2, array3);
    // or
    var bined = array1.concat(array2, array3);

but as we don't know how many args we're going to receive, we have to use apply.

 someFunction.apply(thisObject, [arg1, arg2, etc])

is the same as

 thisObject.someFunction(arg1, arg2, etc)

so the above line

 var bined = [].concat(array1, array2, array3);

can be written as

 var bined = concat.apply([], [array1, array2, array3]);

or simply

 var bined = concat.apply([], arguments);

where arguments is a special array-like object that contains all function arguments (actual parameters).

Actually, last two lines are not going to work, because concat isn't a plain function, it's a method of Array objects and therefore a member of Array.prototype structure. We have to tell the JS engine where to find concat. We can use Array.prototype directly:

 var bined = Array.prototype.concat.apply([], arguments);

or create a new, unrelated, array object and pull concat from there:

 var bined = [].concat.apply([], arguments);

This prototype method is slightly more efficient (since we're not creating a dummy object), but also more verbose.

Anyways, the first step is now plete. To eliminate duplicates, we use the following method:

 bined.filter(function(elem, index) {
     return bined.indexOf(elem) === index;
 })

For explanations and alternatives see this post.

Finally, we get rid of the temporary variable (bined) and chain "bine" and "dedupe" calls together:

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

using the 3rd argument ("this array") of filter because we don't have a variable anymore.

Simple, isn't it? ;) Let us know if you have questions.

Finally, a small exercise if you're interested:

Write bine and dedupe as separate functions. Create a function pose that takes two functions a and b and returns a new function that runs these functions in reverse order, so that pose(a,b)(argument) will be the same as b(a(argument)). Replace the above definition of unite with unite = pose(bine, dedupe) and make sure it works exactly the same.

You can also try this :

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)

发布评论

评论列表(0)

  1. 暂无评论