Trying to solve symmetric difference using Javascript
Trying to solve symmetric difference using Javascript
I am trying to figure out a solution for symmetric difference using javascript that accomplishes the following objectives:
- accepts an unspecified number of arrays as arguments
- preserves the original order of the numbers in the arrays
- does not remove duplicates of numbers in single arrays
- removes duplicates occurring across arrays
Thus, for example, if the input is ([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]), the solution would be, [1, 1, 6, 5, 4].
I am trying to solve this as challenge given by an online coding community. The exact instructions of the challenge state,
Create a function that takes two or more arrays and returns an array of the symmetric difference of the provided arrays.
The mathematical term symmetric difference refers to the elements in two sets that are in either the first or second set, but not in both.
Although my solution below finds the numbers that are unique to each array, it eliminates all numbers occuring more than once and does not keep the order of the numbers.
My question is very close to the one asked at finding symmetric difference/unique elements in multiple arrays in javascript. However, the solution does not preserve the original order of the numbers and does not preserve duplicates of unique numbers occurring in single arrays.
function sym(args){ var arr = []; var result = []; var units; var index = {}; for(var i in arguments){ units = arguments[i]; for(var j = 0; j < units.length; j++){ arr.push(units[j]); } } arr.forEach(function(a){ if(!index[a]){ index[a] = 0; } index[a]++; }); for(var l in index){ if(index[l] === 1){ result.push(+l); } } return result; } symsym([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]); // => Desired answer: [1, 1, 6. 5. 4]
Answer by jfriend00 for Trying to solve symmetric difference using Javascript
Here's a version that uses the Set
object to make for faster lookup. Here's the basic logic:
- It puts each array passed as an argument into a separate Set object (to faciliate fast lookup).
- Then, it iterates each passed in array and compares it to the other Set objects (the ones not made from the array being iterated).
- If the item is not found in any of the other Sets, then it is added to the result.
So, it starts with the first array [1, 1, 2, 6]
. Since 1
is not found in either of the other arrays, each of the first two 1
values are added to the result. Then 2
is found in the second set so it is not added to the result. Then 6
is not found in either of the other two sets so it is added to the result. The same process repeats for the second array [2, 3, 5]
where 2
and 3
are found in other Sets, but 5
is not so 5
is added to the result. And, for the last array, only 4
is not found in the other Sets. So, the final result is [1,1,6,5,4]
.
The Set
objects are used for convenience and performance. One could use .indexOf()
to look them up in each array or one could make your own Set-like lookup with a plain object if you didn't want to rely on the Set object. There's also a partial polyfill for the Set object that would work here in this answer.
function symDiff() { var sets = [], result = []; // make copy of arguments into an array var args = Array.prototype.slice.call(arguments, 0); // put each array into a set for easy lookup args.forEach(function(arr) { sets.push(new Set(arr)); }); // now see which elements in each array are unique // e.g. not contained in the other sets args.forEach(function(array, arrayIndex) { // iterate each item in the array array.forEach(function(item) { var found = false; // iterate each set (use a plain for loop so it's easier to break) for (var setIndex = 0; setIndex < sets.length; setIndex++) { // skip the set from our own array if (setIndex !== arrayIndex) { if (sets[setIndex].has(item)) { // if the set has this item found = true; break; } } } if (!found) { result.push(item); } }); }); return result; } var r = symDiff([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]); log(r); function log(x) { var d = document.createElement("div"); d.textContent = JSON.stringify(x); document.body.appendChild(d); }
One key part of this code is how it compares a given item to the Sets from the other arrays. It just iterates through the list of Set objects, but it skips the Set object that has the same index in the array as the array being iterated. That skips the Set made from this array so it's only looking for items that exist in other arrays. That allows it to retain duplicates that occur in only one array.
Here's a version that uses the Set
object if it's present, but inserts a teeny replacement if not (so this will work in more older browsers):
function symDiff() { var sets = [], result = [], LocalSet; if (typeof Set === "function") { try { // test to see if constructor supports iterable arg var temp = new Set([1,2,3]); if (temp.size === 3) { LocalSet = Set; } } catch(e) {} } if (!LocalSet) { // use teeny polyfill for Set LocalSet = function(arr) { this.has = function(item) { return arr.indexOf(item) !== -1; } } } // make copy of arguments into an array var args = Array.prototype.slice.call(arguments, 0); // put each array into a set for easy lookup args.forEach(function(arr) { sets.push(new LocalSet(arr)); }); // now see which elements in each array are unique // e.g. not contained in the other sets args.forEach(function(array, arrayIndex) { // iterate each item in the array array.forEach(function(item) { var found = false; // iterate each set (use a plain for loop so it's easier to break) for (var setIndex = 0; setIndex < sets.length; setIndex++) { // skip the set from our own array if (setIndex !== arrayIndex) { if (sets[setIndex].has(item)) { // if the set has this item
Answer by torazaburo for Trying to solve symmetric difference using Javascript
As with all problems, it's best to start off writing an algorithm:
Concatenate versions of the arrays, where each array is filtered to contain those elements which no array other than the current one contains
Then just write that down in JS:
function sym() { var arrays = [].slice.apply(arguments); return [].concat.apply([], // concatenate arrays.map( // versions of the arrays function(array, i) { // where each array return array.filter( // is filtered to contain function(elt) { // those elements which return !arrays.some( // no array function(a, j) { // return i !== j // other than the current one && a.indexOf(elt) >= 0 // contains ; } ); } ); } ) ); }
Non-commented version, written more succinctly using ES6:
function sym(...arrays) { return [].concat(arrays . map((array, i) => array . filter(elt => !arrays . some((a, j) => i !== j && a.indexOf(elt) >= 0)))); }
Answer by Angshuman Gupta for Trying to solve symmetric difference using Javascript
This is the JS code using higher order functions
function sym(args) { var output; output = [].slice.apply(arguments).reduce(function(previous, current) { current.filter(function(value, index, self) { //for unique return self.indexOf(value) === index; }).map(function(element) { //pushing array var loc = previous.indexOf(element); a = [loc !== -1 ? previous.splice(loc, 1) : previous.push(element)]; }); return previous; }, []); document.write(output); return output; } sym([1, 2, 3], [5, 2, 1, 4]);
And it would return the output as: [3,5,4]
Answer by kornieff for Trying to solve symmetric difference using Javascript
Just use _.xor or copy lodash code.
Answer by vinayakj for Trying to solve symmetric difference using Javascript
Pure javascript solution.
function diff(arr1, arr2) { var arr3= []; for(var i = 0; i < arr1.length; i++ ){ var unique = true; for(var j=0; j < arr2.length; j++){ if(arr1[i] == arr2[j]){ unique = false; break; } } if(unique){ arr3.push(arr1[i]);} } return arr3; } function symDiff(arr1, arr2){ return diff(arr1,arr2).concat(diff(arr2,arr1)); } symDiff([1, "calf", 3, "piglet"], [7, "filly"]) //[1, "calf", 3, "piglet", 7, "filly"]
Answer by Mohsen Kadoura for Trying to solve symmetric difference using Javascript
I tested a couple of the last answers they do not give the correct return value for more than two arrays, thus unfulfilling the very first conditions of the asked question!
Here is a quick and pretty straight forward answer fulfilling also this first condition (You are welcome to refactor it, in a simple manner(read easily maintainable and professional) please, as I didn't refactor it for reasons of educational simplicity and clarity of the algorithm I devised for this question ):
function sym() { var argmnts = Array.prototype.slice.call(arguments); // The diff function takes two arrays and return a new array with unique values. function diff(arr1, arr2) { var collect1 = arr2.filter(function(val) { return arr1.indexOf(val) === -1; }); var collect2 = arr1.filter(function(val) { return arr2.indexOf(val) === -1; }); // After concating the lastest two arrays the resultant array is refiltered for unique values. var collect = collect2.concat(collect1).filter(function(val, indx, arr) { return arr.indexOf(val) === indx; }); return collect; } // The reduce function iterates over the supplied arguments/arrays to the sym function returning the overall symetric diffrence for them. return argmnts.reduce(diff, []); } sym([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]) // the solution would be, [1, 1, 6, 5, 4].
Answer by Tim Reznik for Trying to solve symmetric difference using Javascript
My short solution. At the end, I remove duplicates by filter(). Feel obligated to upvote it ;)
function sym() { var args = Array.prototype.slice.call(arguments); var almost = args.reduce(function(a,b){ return b.filter(function(i) {return a.indexOf(i) < 0;}) .concat(a.filter(function(i){return b.indexOf(i)<0;})); }); return almost.filter(function(el, pos){return almost.indexOf(el) == pos;}); } sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]); //Result: [4,5,1]
Answer by jpl1079 for Trying to solve symmetric difference using Javascript
I came across this question in my research of the same coding challenge on FCC. I was able to solve it using for
and while
loops, but had some trouble solving using the recommended Array.reduce()
. After learning a ton about .reduce
and other array methods, I thought I'd share my solutions as well.
This is the first way I solved it, without using .reduce
.
function sym() { var arrays = [].slice.call(arguments); function diff(arr1, arr2) { var arr = []; arr1.forEach(function(v) { if ( !~arr2.indexOf(v) && !~arr.indexOf(v) ) { arr.push( v ); } }); arr2.forEach(function(v) { if ( !~arr1.indexOf(v) && !~arr.indexOf(v) ) { arr.push( v ); } }); return arr; } var result = diff(arrays.shift(), arrays.shift()); while (arrays.length > 0) { result = diff(result, arrays.shift()); } return result; }
After learning and trying various method combinations, I came up with this that I think is pretty succinct and readable.
function sym() { var arrays = [].slice.call(arguments); function diff(arr1, arr2) { return arr1.filter(function (v) { return !~arr2.indexOf(v); }); } return arrays.reduce(function (accArr, curArr) { return [].concat( diff(accArr, curArr), diff(curArr, accArr) ) .filter(function (v, i, self) { return self.indexOf(v) === i; }); }); }
That last .filter
line I thought was pretty cool to dedup an array. I found it here, but modified it to use the 3rd callback parameter instead of the named array due to the method chaining.
This challenge was a lot of fun!
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment