Sorted Union challenge, what's wrong with filter()?

Sorted Union challenge, what's wrong with filter()?
0

#1

I have already solved “Sorted Union”, here is my code that passes the test (this is not the question yet :slight_smile: ):

function uniteUnique(arr) {
  // flatten arguments into a single array:
  var i = 0;
  var allArgs = [];
  while ( arguments[i] ) {
    allArgs = allArgs.concat( arguments[i] );
    i++;
  }   
  
  // filter unique values from allArgs:  (this works)
  var result = [];
  for ( let x of allArgs ) {    
    if ( result.indexOf( x ) < 0 ) {
      result.push( x );
    }    
  }   
  return result;
}

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

Then I tried to rewrite the second ‘for’ loop with a .filter() instead. The logic is the same: for each element, check if it already exists in result and only add it if it does not. However, this code fails all tests, as filter() seems to pass through all values. The code:

function uniteUnique() {
  // flatten arguments into a single array:
  var i = 0;
  var allArgs = [];
  while ( arguments[i] ) {
    allArgs = allArgs.concat( arguments[i] );
    i++;
  }   
  
  // filter unique values from allArgs: (This does NOT work)
  var result = [];
  result = allArgs.filter( function( x ) {
    return result.indexOf( x ) < 0;
  } );  
  
  return result;
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);

My best guess is that the result array does not get updated while filter() is being executed, so indexOf() always returns -1, but is this right?

On edit: In fact, yes, this is how filter() seems to work, but I still can’t understand why! A simplest possible testcase:

<script>
var ar1 = [1,1]; // original array
var ar2 = []; // put only UNIQUE values here
ar2 = ar1.filter( function( x ) {
     // return true only if x is not yet in ar2
     return ( ar2.indexOf(x) < 0 );
})
console.log( ar2 );
</script>

Result is:
Array [ 1, 1 ]
so indeed, it seems that the resulting array cannot be read inside filter(). And I thought I understood filter()…


#2

Here you go …

     ( result.indexOf(x)  < 0) ? result.push(x):false;
  } );```

#3

push() is what I do in my first (working) solution. But isn’t filter() already supposed to be pushing values onto the resulting array if the callback returns true?


#4

No filter is just a handy way of pulling each item out of an array for us then to work with

    d(result.indexOf( x )<0);
    return (result.indexOf( x ) < 0)? result.push(x):false;
  } ); ````

  return result.indexOf( x ) < 0  seems to be  result.indexOf( x ) < 0 = true  ...then return true
still need to to push the true ones  into the array

#5

Thank you for staying with me, but looking at the docs, you don’t need to push values explicitly: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

“The filter() method creates a new array with all elements that pass the test implemented by the provided function.”

function isBigEnough(value) {
  return value >= 10;
 }

 var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
 // filtered is [12, 130, 44]

No push is needed; filter creates the resulting array “by itself”. What am I missing?


#6


here is a lesson I made for my students on this topic.


#7

look at this … i redid your problem based on mozilla link even used the isBigEnough function modified for your problem
your missing that that is working with an array that has values and just checking is each value > =10 … while you are checking if index of the values in the allArgs array are <0 in the result array so when it checks the first value the result array is empty and returns true checks next and doses same till all checked

AND THEN at the end of checking returns all the values that are true which will be all of them … i was missing this point

when you push a value in if its less than 0 then when next value is checked there is a value in the result array so if its a duplicate value it wont be <0 and will be false and thats not returned
and thats why you need to push the true values in
hope this explanation helps

have a look at below on lines 15 and 16 add and remove // and look at the console

I updated repl to show result array each time a value is checked … should make things crystal clear what happens