freeCodeCamp Challenge Guide: Sorted Union

Sorted Union


Problem Explanation

The program has to return a new array of unique values from two original arrays in the order they show up. So there is not sorting required, and there shouldn’t be any duplicates.

Relevant Links


Hints

Hint 1

Since you have no idea how many parameters were passed, it would be best to loop through the arguments before looping through the arrays.

Hint 2

It isn’t necessary to use loops. You can use functions such as map(), reduce() or others if you want.

Hint 3

You will have to check if the current value is already on the array to be returned for every value.


Solutions

Solution 1 (Click to Show/Hide)
function uniteUnique(arr1, arr2, arr3) {
  // Creates an empty array to store our final result.
  const finalArray = [];

  // Loop through the arguments object to truly make the program work with two or more arrays
  // instead of 3.
  for (let i = 0; i < arguments.length; i++) {
    const arrayArguments = arguments[i];

    // Loops through the array at hand
    for (let j = 0; j < arrayArguments.length; j++) {
      let indexValue = arrayArguments[j];

      // Checks if the value is already on the final array.
      if (finalArray.indexOf(indexValue) < 0) {
        finalArray.push(indexValue);
      }
    }
  }

  return finalArray;
}

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

Code Explanation

  • Create empty array finalResult to store the final result.
  • Loop through the arguments object in the outer loop and store it in arrayArguments.
  • The inner loop is used to loop through individual array elements.
  • If the element doesn’t already exist in finalArray, add it.
  • Return finalArray.

Relevant Links

Solution 2 (Click to Show/Hide)
function uniteUnique(arr) {
  const args = [...arguments];
  const result = [];
  for (let i = 0; i < args.length; i++) {
    for (let j = 0; j < args[i].length; j++) {
      if (!result.includes(args[i][j])) {
        result.push(args[i][j]);
      }
    }
  }
  return result;
}

uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
Solution 3 (Click to Show/Hide)
function uniteUnique(...arr) {
  return [...new Set(arr.flat())];
}

// Or as an arrow function
const uniteUnique = (...arr) => [...new Set(arr.flat())];

Relevant Links

Solution 4 (Click to Show/Hide)
function uniteUnique() {
  return [...arguments]
    .flat()
    .filter((item, ind, arr) => arr.indexOf(item) === ind);
}

uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
111 Likes
function uniteUnique(arr) {
  var args = Array.from(arguments);
  var uniqueValues = [];

  for (var i = 0; i < args.length; i++) {
    for (var j = 0; j < args[i].length; j++) {
      if (!uniqueValues.includes(args[i][j])) {
        uniqueValues.push(args[i][j]);
      }
    }
  }

  return uniqueValues;
}
41 Likes

Here’s mine:

function uniteUnique(arr) {
  var uniqueArr = Array.from(arguments).reduce(function(a, b) {
    return a.concat(b);
  }, []);

  var i = 0, max = uniqueArr.length;
  
  while(i < max) {
    max = uniqueArr.length;
    
    for(var j = i + 1; j < max; j++) {
      if(uniqueArr[i] === uniqueArr[j]) {
        uniqueArr.splice(j, 1);
      }      
    }    
    i++;
  }
  
  return uniqueArr;
}
4 Likes

Here’s mine.

I used a spread operator to assign all arrays in the arguments object to one array, then iterated over them with reduce and find to remove the duplicate results.

function uniteUnique(arr) {
  const numbers = [].concat(...arguments);
  return numbers.reduce(function(reducedNumbers, number){
  	if (!reducedNumbers.find(reducedNumber => { return reducedNumber === number; })) {
    	reducedNumbers.push(number);
    }
    return reducedNumbers;
  }, []);
}

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

How does this look for the advanced solution?

function uniteUnique() {

  return (
    //Get all the arguments into an array
    Array.from(arguments)
    
    //Flatten the arrays within the array
    .reduce(function(a, b){ 
      return a.concat(b);}, [])
    
    //Filter out the duplicates
    .filter(function(val, i, arr){ 
      return arr.indexOf(val) == i;})
  )
}
20 Likes

This also works. We can grab all arguments with …arr, run concat on the array, and then filter it out on the go.

function uniteUnique(...arr) {
          return arr.reduce(function(all,item){
             return all.concat(item).filter(function(el,index,self){
                 return index == self.indexOf(el);
             });
          });
        }
2 Likes

Nice code, but I think the solution above yours is better, since you call ‘.filter()’ after every ‘.concat()’, which is unnecessary (and thus less efficient).

My one line solution

function uniteUnique(...arr) {
  return arr.reduce((a, c)=>a.concat(c.filter(v => a.indexOf(v) == -1)),[]);
}
30 Likes

This is my solution using ES6

   function uniteUnique(arr) {

    function remove_duplicates_es6(arr) {
        let s = new Set(arr);
        let it = s.values();
        return Array.from(it);
    }

    let newArr = [];

    newArr.push(arguments);

    for (let i in newArr) {

        let array = $.map(newArr[i], function(value, index) {
            return [value];
        });
        let flattened = array.reduce((a, b) => a.concat(b), []);
        return remove_duplicates_es6(flattened);

    }

}

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

or just the oneliner

return [...new Set(Array.from(arguments).reduce((a, b) => a.concat(b)))];

4 Likes

my red-headed stepchild:


function uniteUnique(arr) {
  var arr1 = [];
  for(var i of arguments) {
    for(var k of i) {
      if(arr1.indexOf(k) === -1) {
        arr1.push(k);
      }
    }
  }
  arr = arr1;
  return arr;
}

11 Likes

My solution :slight_smile:
function uniteUnique(arr) {
var args = Array.prototype.slice.call(arguments),finalArr=[];

  for(var i=0;i<args.length;i++){
   args[i].forEach(function(element){
       if(!finalArr.includes(element)){
         finalArr.push(element);
       }
    });
    
  }
  return finalArr;
}
3 Likes

My Code:

function uniteUnique(arr) {
  //get the first parameter to compare arrays to
  var arr1 = arguments[0];
  //loop through arguments
  for(var i=1; i<arguments.length; i++){
    var arg = arguments[i];
    //loop through each argument array
    for(var y=0; y<arg.length; y++){
      while(arr1.indexOf(arg[y]) != -1){
        arg.splice(y, 1);//remove all dublicates from current argument
      }
    }
    arr1 = arr1.concat(arg);//concatenate arrays with no dublicates
  }
  return arr1;
}
//test
uniteUnique([1, 3, 2], [1, [5]], [2, [4]]);

Why cannot we make use of Map ?

I over-complicated it after mis-reading the prompt. But, this one will flatten all of the arrays before putting them in place, so you end up with just a single-level array. Now to go back and remove all the flattening so it meets the criteria to move on :slight_smile:

function flatten(arr){
  return arr.reduce(function(accum, val){
    if(Array.isArray(val)){
      return accum.concat(flatten(val)); //recursion on arrays
    }else{
      return accum.concat(val);
    }
  },[]);
}

function uniteUnique(arr) {
  var retArr =[];
 
  for (var i=1; i<arguments.length;i++){ //start at 1 b/c arr includes 0 index
    arr.push(flatten(arguments[i]));
  }//array of flat arrays
  
  arr = flatten(arr); //now a flat array
  
  for (i=0;i<arr.length;i++){
    if(!retArr.includes(arr[i])){
      retArr.push(arr[i]);
    }
     
  }
  
  return retArr;
}

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

You can use map. Check out my solution here:

function uniteUnique(arr) {
  var newArr = [];
  var arg = [].slice.call(arguments);
  
  function onlyUnique(value, index, self) { 
    return self.indexOf(value) === index;
  }
  
  arg.map(function(val){
    val.map(function(ind){
      newArr.push(ind);
    });
  });
  
  return newArr.filter(onlyUnique);
}

Couple of my solutions - bottom one was what I came up with first, the second was just to try to use reduce since it was offered as a hint:

function test(...arg) { 
  let x = arg.reduce((prv, cur) => prv.concat(cur)),
  y = x.filter((v,p) => (v != undefined) ? x.indexOf(v) == p : undefined)
  console.log(y)
}

test([1, 2, 3], [5, 2, 1]);




function uniteUnique(arr) { 
  const arg0 = arguments[0],
        arg1 = arguments[1],
        arg2 = arguments[2],
        arg3 = arguments[3],
        
        concatArr = arg0.concat(arg1, arg2, arg3);
  
  let output = concatArr.filter((elem, pos) => {
    if (elem != undefined) {
      return concatArr.indexOf(elem) === pos;
    }
  });
  
  console.log(output);
  return output
}

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

function uniteUnique(arr) {
var args = Array.from(arguments);
var newArr = [];
for (var k = 0; k < args.length; k++) {
newArr = newArr.concat(args[k]);
}
for (var i = 0; i < newArr.length; i++) {
for (var j = i + 1; j < newArr.length; j++) {
if (newArr[i] === newArr[j]) {
newArr.splice(j, 1);
i–;
}
}
}
return newArr;
}

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

1 Like

I thought I came up with an original solution but then I came here it’s pretty similar to all the others :laughing:. Good to know I’m on the right track though. I’m really enjoying these challenges.


function uniteUnique(arr) {
 var newArr = arguments[0];
  for (var i = 0; i < arguments.length; i++){
    for (var j = 0; j < arguments[i].length; j++){
      if (newArr.indexOf(arguments[i][j]) === -1){
 newArr.push(arguments[i][j]);
   }
  }
 }
  return newArr;
}

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

1 Like