freeCodeCamp Challenge Guide: Sorted Union

freeCodeCamp Challenge Guide: Sorted Union
0

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.
  var finalArray = [];

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

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

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

  return finalArray;
}

// test here
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) {
  var args = [...arguments];
  var result = [];
  for (var i = 0; i < args.length; i++) {
    for (var 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(arr1, arr2, arr3) {
  var newArr;
  //Convert the arguments object into an array
  var args = Array.prototype.slice.call(arguments);
  //Use reduce function to flatten the array
  newArr = args.reduce(function(arrA, arrB) {
    //Apply filter to remove the duplicate elements in the array
    return arrA.concat(
      arrB.filter(function(i) {
        return arrA.indexOf(i) === -1;
      })
    );
  });

  return newArr;
}

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

Code Explanation

  • arguments object is converted into an array using slice().
  • reduce() function is used to flatten the array i.e., for every element that is in the array (or nested arrays), extract it’s elements into one-dimensional array.
  • After flattening the array, filter() is used to remove duplicate elements from newArr.

Relevant Links

Solution 4 (Click to Show/Hide)
function uniteUnique() {
  var concatArr = [];
  var i = 0;
  while (arguments[i]) {
    concatArr = concatArr.concat(arguments[i]);
    i++;
  }
  uniqueArray = concatArr.filter(function(item, pos) {
    return concatArr.indexOf(item) == pos;
  });
  return uniqueArray;
}

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

Code Explanation

  • Number of arguments can change dynamically, so we don’t need to bother providing our function uniteUnique() with arguments at all.
  • We use a while loop to concatenate all the arguments into one array called concatArr.
  • We use filter() to remove the duplicate elements by checking the index of each element and removing same elements with different positions.
  • Ordering will be preserved here.

Relevant Links

Solution 5 (Click to Show/Hide)

Alternative Code Solution using ES2015

//jshint esversion:6

function uniteUnique(...arrays) {
  //make an array out of the given arrays and flatten it (using the spread operator)
  const flatArray = [].concat(...arrays);

  // create a Set which clears any duplicates since it's a regulat set and not a multiset
  return [...new Set(flatArray)];
}

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

Code Explanation

  • We first use concat() with an empty array as a starting point and the spread operator ... to create an array out of the Arguments object and to flatten it at the same time
  • then we use the new ES2015 Set object to store only unique values

Relevant Links

7 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;
}
23 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;
}
1 Like

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

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;})
  )
}
7 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);
             });
          });
        }
1 Like

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)),[]);
}
15 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)))];

1 Like

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

4 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;
}
1 Like

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