Related
my English is not good but i really need your help.
I want to reduce all same values in this 2 Dimensional Array but it doesn't work.
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
for (let i = 0; i < edge.length; i++) {
if (edge.some((item) => item > 1)) {
edge.splice(i, 1);
}
}
return edge;
}
i want to change array like this.
[[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]]
to
[[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
Use the the filter() array method with the every() array method as shown below:
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
return edge.filter(
(cur,i) => edge.slice(0,i).every(
prev => !prev.every(elm => cur.includes(elm))
)
);
}
console.log( removeDup(edge) );
//output: [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4]]
If your goal is to remove all elements that are repeated, you would need to use the whole array, edge, instead of edge.slice(0,i) and, avoid comparing an element with itself - i !== j - as shown below:
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
return edge.filter(
(cur,i) => edge.every(
(prev,j) => !prev.every(elm => i !== j && cur.includes(elm))
)
);
}
console.log( removeDup(edge) );
//output: [[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
Another approach would be:
To convert each element array to a single value by first sorting the elements and joining them
Then use filter() to only return the element array that return a frequency of 1
Use an inner filter() to count how many times each converted element appears in the array.
[...cur] ensures original elements are not sorted, since arrays are passed by reference.
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
function removeDup(edge) {
const nedge = edge.map(cur => [...cur].sort().join(''));
return edge.filter(
cur => nedge.filter(
n => n === [...cur].sort().join('')
).length === 1
);
}
console.log( removeDup(edge) );
//output: [[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
This may be one possible solution to achieve the desired result:
Copying from the question:
[[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]]
to
[[0,1,4],[1,2,4],[2,3,4],[3,0,4]]
Note: The desired target array has no [0, 2, 4].
Code Sample
const removeDupes = arr => (
Object.entries(
arr.reduce(
(fin, itm) =>
({...fin, [itm]: (fin[itm] || 0) + 1})
,{}
)
).filter(
([k ,v]) => v === 1
).map(x => x[0])
);
Explanation
Iterate over the array using .reduce to generate an object
The key of the resulting object will be each inner array (such as [0, 1, 4]
The value will be a count (number of times the inner array is found in edge)
Once the object is generated, iterate over its entries to filter only those which have a count of exactly 1
Now, use .map to pull only the keys of the object.
Code Snippet
let edge = [[0,1,4],[1,2,4],[0,2,4],[2,3,4],[3,0,4],[0,2,4]];
const removeDupes = arr => (
Object.entries(
arr.reduce(
(fin, itm) =>
({...fin, [itm]: (fin[itm] || 0) + 1})
,{}
)
).filter(
([k ,v]) => v === 1
).map(x => x[0])
);
console.log(removeDupes(edge));
This is the solution by using the reduce() method.
let edge = [
[0, 1, 4],
[1, 2, 4],
[0, 2, 4],
[2, 3, 4],
[3, 0, 4],
[0, 2, 4],
];
function removeDuplicate(edge) {
return edge.reduce((acc, cur) => {
!acc.some((elm) => elm.every((e, i) => cur[i] === e)) && acc.push(cur);
return acc;
}, []);
}
console.log(removeDuplicate(edge));
I'm trying to solve this task of finding the unique element inside an array.
So far I managed to solve 95%, but I'm failing on 0. I get an error saying that expected 0 and got 1.
I should get //10, which it does, but after I'm failing the test online. For all other values it has passed.
Any ideas about how to solve this and what I'm missing here?
function findOne(arr) {
let x = arr[0];
for (let i of arr) {
if (i === x) {
continue;
} else {
x = i;
}
return x;
}
}
console.log(findOne([3, 10, 3, 3, 3]));
I don't really understand your code. You start with the first value in the array, then you loop through the array, skipping anything that's the same, and then return the first one that's not the same. That won't find unique values, it'll just find the first value that doesn't equal the first value. So for instance, try it on the array [1,2,2,2,2] and you'll get a result of 2 instead of 1, even though that's clearly wrong.
Instead, you can create a map of each value and its incidence, then filter by the ones that equal 1 at the end.
function findOne(arr) {
const incidences = arr.reduce((map, val) => {
map[val] = (map[val] || 0) + 1;
return map;
}, {});
const values = Object.keys(incidences);
for (let i = 0; i < values.length; ++i) {
if (incidences[values[i]] === 1) { return values[i]; }
}
return null;
}
EDIT The above won't preserve the type of the value (i.e. it'll convert it to a string always, even if it was originally a number). To preserve the type, you can use an actual Map instead of an object:
function findOne(arr) {
const incidences = arr.reduce((map, val) => {
map.set(val, (map.get(val) || 0) + 1);
return map;
}, new Map());
const singletons = Array.from(incidences).filter(entry => entry[1] === 1);
return singletons.map(singleton => singleton[0]);
}
Consider the following:
Recall that a span = max - min + 1;
Let Partition P1 be span from 0..span-1;
Let Partition P2 be span from span..(2*span)-1:
Place a number in P1 if it is not in P2.
Place a number in P2 if it is already in P1.
Once the number is in P2, do not consider it again.
If a number is in P1 then it is unique.
You can get all values that appear once, by using a map to count how many times each element has appeared. You can then reduce that map into an array of unique values:
const findUnique = arr => {
const mapEntries = [...arr.reduce((a, v) => a.set(v, (a.get(v) || 0) + 1), new Map()).entries()]
return mapEntries.reduce((a, v) => (v[1] === 1 && a.push(v[0]), a), [])
}
console.log(findUnique([3, 10, 3, 3, 3]))
console.log(findUnique([1, 2, 3, 2, 4]))
console.log(findUnique([4, 10, 4, 5, 3]))
If you don't care about multiple unique values, you can just sort the array and use logic, rather than checking every value, provided the array only contains 2 different values, and has a length greater than 2:
const findUnique = arr => {
a = arr.sort((a, b) => a - b)
if (arr.length < 3 || new Set(a).size === 1) return null
return a[0] === a[1] ? a[a.length-1] : a[0]
}
console.log(findUnique([3, 10, 3, 3, 3]))
console.log(findUnique([3, 3, 1]))
console.log(findUnique([3, 1]))
console.log(findUnique([3, 3, 3, 3, 3]))
Your code is complex, Try this
function findOne(arr) {
const uniqueItems = [];
arr.forEach(item => {
const sameItems = arr.filter(x => x === item);
if (sameItems.length === 1) {
uniqueItems.push(item);
}
});
return uniqueItems;
}
console.log(findOne([0, 1, 1, 3, 3, 3, 4]));
I'm getting all unique items from passed array, It may have multiple unique item
this is a way simpler and fast:
function findOne(arr) {
const a = arr.reduce((acc, e) => {
e in acc || (acc[e] = 0)
acc[e]++
return acc
}, {})
return Object.keys(a).filter(k => a[k] === 1)[0] || null
}
I have this example of code
let numbers = [1, 2, 3]
let summableNum = Object.assign({}, numbers, {
sum: function() {
return this.reduce(function(a, b) {
return a + b
})
}
})
the result is:
{
"0": 1,
"1": 2,
"2": 3,
sum: f
}
summableNum[0] // 1
when i execute summableNum.sum(), i have this error
Uncaught TypeError: this.reduce is not a function
at Object.sum (:4:17)
at :11:17
expected result:
summableNum.sum() // 6
can you help me
Your summableNum is the {} object, which doesn't have a .reduce property. Use an array instead:
const numbers = [1, 2, 3];
const summableNum = Object.assign([], numbers, {
sum() {
return this.reduce((a, b) => a + b, 0);
}
});
Or use a copy of the array:
const numbers = [1, 2, 3];
const summableNum = Object.assign(Array.from(numbers), {
sum() {
return this.reduce((a, b) => a + b, 0);
}
});
Either assign a sum property to the actual array instance, or to Array.prototype (generally not recommended, since it mutates a built-in prototype - it's usually not a good idea to mutate objects you don't own):
const numbers = [1, 2, 3]
// Method 1:
const summableNum1 = [...numbers];
summableNum1.sum = function() {
return this.reduce(function(a, b) {
return a + b
})
};
console.log(summableNum1.sum());
// Method 2:
Array.prototype.sum = function() {
return this.reduce(function(a, b) {
return a + b
})
};
const summableNum2 = [...numbers];
console.log(summableNum2.sum());
A different option is to create a class that extends Array which has the sum method:
// Method 3
class SummableArray extends Array {
sum() {
return this.reduce((a, b) => a + b);
}
}
const numbers = new SummableArray(1, 2, 3);
console.log(numbers.sum());
if you only want nums to have a method sum, then I would avoid attaching it to the prototype... and Object.defineProperty is more appropriate then Object.assign for this job.
const nums = [1, 2, 3];
Object.defineProperty(nums, 'sum', {
value: () => nums.reduce((a, b) => a + b),
});
console.log('[1,2,3].sum() =', nums.sum())
However, the right way to go (in my opinion), is to be more functional...
If you separate the data from its behaviour, the reusing code becomes much easier:
const sum = nums => nums.reduce((a, b) => a + b);
console.log(sum([1, 2, 3]));
// but also sum([55,56,57]) and so on
I'm trying to sum a nested array [1,2,[3,4],[],[5]] without using loops but I don't see what's wrong with what I have so far.
function sumItems(array) {
let sum = 0;
array.forEach((item) => {
if (Array.isArray(item)) {
sumItems(item);
} else {
sum += item;
}
});
return sum;
}
try with
function sumItems(array) {
let sum = 0;
array.forEach((item) => {
if(Array.isArray(item)) {
sum += sumItems(item);
} else {
sum += item;
}
})
return sum;
}
recursion is a functional heritage
Recursion is a concept that comes from functional style. Mixing it with imperative style is a source of much pain and confusion for new programmers.
To design a recursive function, we identify the base and inductive case(s).
base case - the list of items to sum is empty; ie, item is Empty. return 0
inductive case 1 - the list of items is not empty; ie, there must be at least one item. if the item is a list, return its sum plus the sum of the rest of the items
inductive case 2 - there is at least one item that is not an array. return this item plus the sum of the rest of the items
const Empty =
Symbol ()
const sumDeep = ([ item = Empty, ...rest ] = []) =>
item === Empty
? 0
: Array.isArray (item)
? sumDeep (item) + sumDeep (rest)
: item + sumDeep (rest)
console.log
( sumDeep ([ [ 1, 2 ], [ 3, 4 ], [ 5, [ 6, [] ] ] ]) // 21
, sumDeep ([ 1, 2, 3, 4, 5, 6 ]) // 21
, sumDeep ([]) // 0
, sumDeep () // 0
)
As a result of this implementation, all pain and suffering are removed from the program. We do not concern ourselves with local state variables, variable reassignment, or side effects like forEach and not using the return value of a function call.
recursion caution
And a tail-recursive version which can be made stack-safe. Here, we add a parameter cont to represent our continuation which effectively allows us sequence the order of + operations without growing the stack – changes in bold
const identity = x =>
x
const sumDeep = ([ item = Empty, ...rest ] = [], cont = identity) =>
item === Empty
? cont (0)
: Array.isArray (item)
? sumDeep (item, a =>
sumDeep (rest, b =>
cont (a + b)))
: sumDeep (rest, a =>
cont (item + a))
Usage is identitcal
console.log
( sumDeep ([ [ 1, 2 ], [ 3, 4 ], [ 5, [ 6, [] ] ] ]) // 21
, sumDeep ([ 1, 2, 3, 4, 5, 6 ]) // 21
, sumDeep ([]) // 0
, sumDeep () // 0
)
performance enhancement
As #גלעד ברקן points out, array destructuring syntax used above (eg ...rest) create copies of the input array. As demonstrated in his/her answer, an index parameter can be used which will avoid creating copies. This variation shows how the index technique can also be used in a tail-recursive way
const identity = x =>
x
const sumDeep = (items = [], i = 0, cont = identity) =>
i >= items.length
? cont (0)
: Array.isArray (items [i])
? sumDeep (items [i], 0, a =>
sumDeep (items, i + 1, b =>
cont (a + b)))
: sumDeep (items, i + 1, a =>
cont (items [i] + a))
console.log
( sumDeep ([ [ 1, 2 ], [ 3, 4 ], [ 5, [ 6, [] ] ] ]) // 21
, sumDeep ([ 1, 2, 3, 4, 5, 6 ]) // 21
, sumDeep ([]) // 0
, sumDeep () // 0
)
Here's a version without using loops:
function f(arr, i){
if (i == arr.length)
return 0;
if (Array.isArray(arr[i]))
return f(arr[i], 0) + f(arr, i + 1);
return arr[i] + f(arr, i + 1);
}
console.log(f([1,2,[3,4],[],[5]], 0));
You could define a callback for using with Array#reduce, which check if an item is an array and uses this function again for that array.
function add(s, v) {
return Array.isArray(v)
? v.reduce(add, s)
: s + v;
}
var array = [1, 2, [3, 4], [], [5]];
console.log(array.reduce(add, 0));
You may do as follows;
var sumNested = ([a,...as]) => (as.length && sumNested(as)) + (Array.isArray(a) ? sumNested(a) : a || 0);
console.log(sumNested([1,2,3,[4,[5,[6]]],7,[]]));
The function argument designation [a,…as] means that when the function is fed with a nested array like [1,2,3,[4,[5,[6]]],7,[]] then a is assigned to the head which is 1 and as is assigned to the tail of the initial array which is [2,3,[4,[5,[6]]],7,[]]. The rest should be easy to understand.
function arraySum (array) {
if (array.length > 0) {
return arraySum(array[0]) + arraySum(array.slice(1));
}
if (array.length === 0) {
return 0;
} else {
return array;
}
};
This is similar to some of the other solutions but might be easier for some to read:
function Sum(arr) {
if (!arr.length) return 0;
if (Array.isArray(arr[0])) return Sum(arr[0]) + Sum(arr.slice(1));
return arr[0] + Sum(arr.slice(1));
}
console.log(Sum([[1],2,[3,[4,[5,[6,[7,[8,9,10],11,[12]]]]]]])) // 78
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]
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))));
}
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
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);
}
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!
// Set difference, a.k.a. relative compliment
const diff = (a, b) => a.filter(v => !b.includes(v))
const symDiff = (first, ...rest) =>
rest.reduce(
(acc, x) => [
...diff(acc, x),
...diff(x, acc),
],
first,
)
/* - - - */
console.log(symDiff([1, 3], ['Saluton', 3])) // [1, 'Saluton']
console.log(symDiff([1, 3], [2, 3], [2, 8, 5])) // [1, 8, 5]
Just use _.xor or copy lodash code.
Another simple, yet readable solution:
/*
This filters arr1 and arr2 from elements which are in both arrays
and returns concatenated results from filtering.
*/
function symDiffArray(arr1, arr2) {
return arr1.filter(elem => !arr2.includes(elem))
.concat(arr2.filter(elem => !arr1.includes(elem)));
}
/*
Add and use this if you want to filter more than two arrays at a time.
*/
function symDiffArrays(...arrays) {
return arrays.reduce(symDiffArray, []);
}
console.log(symDiffArray([1, 3], ['Saluton', 3])); // [1, 'Saluton']
console.log(symDiffArrays([1, 3], [2, 3], [2, 8, 5])); // [1, 8, 5]
Used functions: Array.prototype.filter() | Array.prototype.reduce() | Array.prototype.includes()
function sym(arr1, arr2, ...rest) {
//creating a array which has unique numbers from both the arrays
const union = [...new Set([...arr1,...arr2])];
// finding the Symmetric Difference between those two arrays
const diff = union.filter((num)=> !(arr1.includes(num) && arr2.includes(num)))
//if there are more than 2 arrays
if(rest.length){
// recurrsively call till rest become 0
// i.e. diff of 1,2 will be the first parameter so every recurrsive call will reduce // the arrays till diff between all of them are calculated.
return sym(diff, rest[0], ...rest.slice(1))
}
return diff
}
Create a Map with a count of all unique values (across arrays). Then concat all arrays, and filter non unique values using the Map.
const symsym = (...args) => {
// create a Map from the unique value of each array
const m = args.reduce((r, a) => {
// get unique values of array, and add to Map
new Set(a).forEach((n) => r.set(n, (r.get(n) || 0) + 1));
return r;
}, new Map());
// combine all arrays
return [].concat(...args)
// remove all items that appear more than once in the map
.filter((n) => m.get(n) === 1);
};
console.log(symsym([1, 1, 2, 6], [2, 3, 5], [2, 3, 4])); // => Desired answer: [1, 1, 6, 5, 4]
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]
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"]
My short solution. At the end, I removed duplicates by filter().
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]
function sym(args) {
var initialArray = Array.prototype.slice.call(arguments);
var combinedTotalArray = initialArray.reduce(symDiff);
// Iterate each element in array, find values not present in other array and push values in combinedDualArray if value is not there already
// Repeat for the other array (change roles)
function symDiff(arrayOne, arrayTwo){
var combinedDualArray = [];
arrayOne.forEach(function(el, i){
if(!arrayTwo.includes(el) && !combinedDualArray.includes(el)){
combinedDualArray.push(el);
}
});
arrayTwo.forEach(function(el, i){
if(!arrayOne.includes(el) && !combinedDualArray.includes(el)){
combinedDualArray.push(el);
}
});
combinedDualArray.sort();
return combinedDualArray;
}
return combinedTotalArray;
}
console.log(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]));
This function removes duplicates because the original concept of symmetric difference operates over sets. In this example, the function operates on the sets this way: ((A △ B) △ C) △ D ...
function sym(...args) {
return args.reduce((old, cur) => {
let oldSet = [...new Set(old)]
let curSet = [...new Set(cur)]
return [
...oldSet.filter(i => !curSet.includes(i)),
...curSet.filter(i => !oldSet.includes(i))
]
})
}
// Running> sym([1, 1, 2, 6], [2, 3, 5], [2, 3, 4])
console.log(sym([1, 1, 2, 6], [2, 3, 5], [2, 3, 4]))
// Return> [1, 6, 5, 2, 4]
This works for me:
function sym() {
var args = [].slice.call(arguments);
var getSym = function(arr1, arr2) {
return arr1.filter(function(each, idx) {
return arr2.indexOf(each) === -1 && arr1.indexOf(each, idx + 1) === -1;
}).concat(arr2.filter(function(each, idx) {
return arr1.indexOf(each) === -1 && arr2.indexOf(each, idx + 1) === -1;
}));
};
var result = getSym(args[0], args[1]);
var len = args.length - 1, i = 2;
while (--len) {
result = [].concat(getSym(result, args[i]));
i++;
}
return result;
}
console.info(sym([1, 1, 2, 5], [2, 2, 3, 5], [6, 8], [7, 8], [9]));
Alternative: Use the lookup inside a map instead of an array
function sym(...vs){
var has = {};
//flatten values
vs.reduce((a,b)=>a.concat(b)).
//if element does not exist add it (value==1)
//or mark it as multiply found value > 1
forEach(value=>{has[value] = (has[value]||0)+1});
return Object.keys(has).filter(x=>has[x]==1).map(x=>parseInt(x,10));
}
console.log(sym([1, 2, 3], [5, 2, 1, 4],[5,7], [5]));//[3,4,7])
Hey if anyone is interested this is my solution:
function sym (...args) {
let fileteredArgs = [];
let symDiff = [];
args.map(arrayEl =>
fileteredArgs.push(arrayEl.filter((el, key) =>
arrayEl.indexOf(el) === key
)
)
);
fileteredArgs.map(elArr => {
elArr.map(el => {
let index = symDiff.indexOf(el);
if (index === -1) {
symDiff.push(el);
} else {
symDiff.splice(index, 1);
}
});
});
return (symDiff);
}
console.log(sym([1, 2, 3, 3], [5, 2, 1, 4]));
Here is the solution
let a=[1, 1, 2, 6]
let b=[2, 3, 5];
let c= [2, 3, 4]
let result=[...a,...b].filter(item=>!(a.includes(item) && b.includes(item) ))
result=[...result,...c].filter(item=>!(b.includes(item) && c.includes(item) ))
console.log(result) //[1, 1, 6, 5, 4]
Concise solution using
Arrow functions
Array spread syntax
Array filter
Array reduce
Set
Rest parameters
Implicit return
const symPair = (a, b) =>
[...a.filter(item => !b.includes(item)),
...b.filter(item => !a.includes(item))]
const sym = (...args) => [...new Set(args.reduce(symPair))]
The function symPair works for two input arrays, and the function sym works for two or more arrays, using symPair as a reducer.
const symPair = (a, b) =>
[...a.filter(item => !b.includes(item)),
...b.filter(item => !a.includes(item))]
const sym = (...args) => [...new Set(args.reduce(symPair))]
console.log(sym([1, 2, 3], [2, 3, 4], [6]))
const removeDuplicates = (data) => Array.from(new Set(data));
const getSymmetric = (data) => (val) => data.indexOf(val) === data.lastIndexOf(val)
function sym(...args) {
let joined = [];
args.forEach((arr) => {
joined = joined.concat(removeDuplicates(arr));
joined = joined.filter(getSymmetric(joined))
});
return joined;
}
console.log(sym([1, 2, 3], [5, 2, 1, 4]));
Below code worked fine all the scenarios. Try the below code
function sym() {
var result = [];
for (var i = 0; i < arguments.length; i++) {
if (i == 0) {
var setA = arguments[i].filter((val) => !arguments[i + 1].includes(val));
var setB = arguments[i + 1].filter((val) => !arguments[i].includes(val));
result = [...setA, ...setB];
i = i + 1;
} else {
var setA = arguments[i].filter((val) => !result.includes(val));
var setB = result.filter((val) => !arguments[i].includes(val));
result = [...setA, ...setB];
}
}
return result.filter((c, index) => {
return result.indexOf(c) === index;
}).sort();
}
My code passed all test cases for the similar question on freecodecamp. Below is code for the same.
function sym(...args) {
const result = args.reduce((acc, curr, i) => {
if (curr.length > acc.length) {
const arr = curr.reduce((a, c, i) => {
if(a.includes(c)){
}
if (!acc.includes(c) && !a.includes(c)) {
a.push(c);
}
if (!curr.includes(acc[i]) && i < acc.length) {
a.push(acc[i])
}
return a;
}, []);
return [...arr];
} else {
const arr = acc.reduce((a, c, i) => {
if(a.includes(c)){
}
if (!curr.includes(c) && !a.includes(c)) {
a.push(c);
}
if (!acc.includes(curr[i]) && i < curr.length) {
a.push(curr[i])
}
return a;
}, []);
return [...arr]
}
});
let ans = new Set([...result])
return [...ans]
}
sym([1,2,3,3],[5, 2, 1, 4,5]);