sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]) should return [1, 4, 5]
The expected return is shown above. But I couldn't find why it fails this test. What kind of fix is needed to code below?
function sym(args) {
//debugger;
var arr=Array.from(arguments);
var resArr=[];
arr.forEach(function(arrVal){
var c=0;
arrVal.forEach(function(val,index){
console.log("arrVal",arrVal,"index",index,"val",val,"|",arrVal.slice(index+1-c));
if(index<arrVal.length-1 && arrVal.slice(index+1-c).indexOf(val)!==-1){
console.log("here");
arrVal.splice(index-c,1);
c++;
}
console.log("arrVal",arrVal,"index",index,"|",arrVal);
});
resArr.push(arrVal);
});
console.log(resArr);
resArr=resArr.reduce(function(acc,curr){
return acc.concat(curr.filter(function(val){
var notContains=acc.indexOf(val)==-1;
if(!notContains)
acc.splice(acc.indexOf(val),1);
return notContains;
}));
},[]);
console.log(resArr);
return resArr;
}
sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);
You could use a more concise version with filtering duplicates.
function sym(array) {
return array.reduce(function (r, a) {
return r.concat(a.filter(function (a, i, aa) {
return i === aa.indexOf(a);
})).filter(function (a, i, aa) {
return aa.indexOf(a) === aa.lastIndexOf(a);
});
}, []);
}
console.log(sym([[1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]])); // [1, 4, 5]
Use Sets. Their support should be sufficent. Extend their prototype and benefit from meaningful methods (union, intersection and difference taken from MDN):
Set.prototype.union = function(setB) {
var union = new Set(this);
for (var elem of setB) {
union.add(elem);
}
return union;
}
Set.prototype.intersection = function(setB) {
var intersection = new Set();
for (var elem of setB) {
if (this.has(elem)) {
intersection.add(elem);
}
}
return intersection;
}
Set.prototype.difference = function(setB) {
var difference = new Set(this);
for (var elem of setB) {
difference.delete(elem);
}
return difference;
}
Set.prototype.symmetricDifference = function(setB) {
return this.union(setB).difference(this.intersection(setB));
}
var set1 = new Set([1, 1, 2, 5]);
var set2 = new Set([2, 2, 3, 5]);
var set3 = new Set([3, 4, 5, 5]);
var result = set1.symmetricDifference(set2).symmetricDifference(set3);
console.log(result); // as Set
console.log([...result]); // as Array
Related
I have two arrays:
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
Using arr1 as the baseline, arr2 does not match because it contains three 1's whereas arr1 only has two. arr3, however should return true because it has elements from arr1.
I tried
if(_.difference(arr2, arr1).length === 0)
But this does not take into account the number of occurrences
You could count all value from the first array and iterate the second with every and return early if a value is not given or zero, otherwise decrement the count and go on.
function check(a, b) {
var count = a.reduce((o, v) => (o[v] = (o[v] || 0) + 1, o), {});
return b.every(v => count[v] && count[v]--);
}
var arr1 = [1, 2, 3, 1, 2, 3, 4],
arr2 = [1, 3, 1, 1],
arr3 = [1, 1, 2, 2, 3];
console.log(check(arr1, arr2)); // false
console.log(check(arr1, arr3)); // true
You can try to loop through second array and compare t against main array if value found make main array cell to false and set flag as true
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
function checkArray(compareMe, toThis){
var flag = false;
for(var i = 0; i < toThis.length; i++){
flag = false;
for(var j = 0; j < compareMe.length; j++){
if(compareMe[j] == toThis[i]){
compareMe[j] = false;
flag = true;
break;
}
}
}
return flag;
}
console.log(checkArray(arr1, arr2));
console.log(checkArray(arr1, arr3));
Try this solution:
const arr1 = [1, 2, 3, 1, 2, 3, 4],
arr2 = [1, 3, 1, 1],
arr3 = [1, 1, 2, 2, 3],
arr4 = [1, 2, 3, 1, 2, 3, 4, 1];
function containsFn(src, trg) {
const srcCp = src.slice();
for(let i = 0; i < trg.length; i++) {
const index = srcCp.indexOf(trg[i]);
if(index > - 1) {
srcCp.splice(index, 1);
} else {
return false;
}
}
return true;
}
console.log(containsFn(arr1, arr2));
console.log(containsFn(arr1, arr3));
console.log(containsFn(arr1, arr4));
Looks like I'm already late to the party but this would be a recursive solution:
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
function findAllIn(find, search) {
if (find.length == 0) {
return true;
}
i = search.indexOf(find[0]);
if (i == -1) {
return false;
}
return findAllIn(find.slice(1,find.length), search.slice(0,i).concat(search.slice(i+1, search.length)));
}
console.log(findAllIn(arr2, arr1)); // false
console.log(findAllIn(arr3, arr1)); // true
This should do the trick
Not efficient but I think it is easy to understand
const count = (x, xs) =>
xs.reduce((y, xi) => y + (xi === x ? 1 : 0), 0)
const isInclusive = (xs, ys) =>
xs.every((xi) => count(xi, xs) >= count(xi, ys))
const arr1 = [1, 2, 3, 1, 2, 3, 4]
const arr2 = [1, 3, 1, 1]
const arr3 = [1, 1, 2, 2, 3]
console.log(isInclusive(arr1, arr2))
console.log(isInclusive(arr1, arr3))
Based on this answer: https://stackoverflow.com/a/4026828/3838031
You can do this:
Array.prototype.diff = function(a) {
return this.filter(function(i) {return a.indexOf(i) < 0;});
};
arr1 = [1, 2, 3, 1, 2, 3, 4]
arr2 = [1, 3, 1, 1]
arr3 = [1, 1, 2, 2, 3]
console.log((arr1.diff(arr2).length === 0) ? "True" : "False");
console.log((arr1.diff(arr3).length === 0) ? "True" : "False");
console.log((arr2.diff(arr1).length === 0) ? "True" : "False");
console.log((arr2.diff(arr3).length === 0) ? "True" : "False");
console.log((arr3.diff(arr1).length === 0) ? "True" : "False");
console.log((arr3.diff(arr2).length === 0) ? "True" : "False");
I couldn't find an answer to this specific question on S.O.
Let's say I have an array of strings, or in this case, numbers:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
I'd like the output to be:
var output = [[1,1,1], [2], [3,3,3,3,3], [4], [5, 5, 5]];
I was hoping to use Lodash but most of that stuff tends to remove duplicates rather chunk them together into their own array. Maybe some kind of .map iterator?
The order of the output doesn't really matter so much. It just needs to chunk the duplicates into separate arrays that I'd like to keep.
You can use reduce to group the array elements into an object. Use Object.values to convert the object into an array.
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
var result = Object.values(x.reduce((c, v) => {
(c[v] = c[v] || []).push(v);
return c;
}, {}));
console.log(result);
Shorter version:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
var result = Object.values(x.reduce((c, v) => ((c[v] = c[v] || []).push(v), c), {}));
console.log(result);
You can do this with Array.reduce in a concise way like this:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5]
let result = x.reduce((r,c) => (r[c] = [...(r[c] || []), c],r), {})
console.log(Object.values(result))
The exact same with lodash would be:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5]
let result = _.values(_.groupBy(x))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Using _.values to extract the values of the grouping object and _.groupBy to get the actual groupings
Use Array#prototype#reduce to group them:
const x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
let helperObj = {};
const res = x.reduce((acc, curr) => {
// If key is not present then add it
if (!helperObj[curr]) {
helperObj[curr] = curr;
acc.push([curr]);
}
// Else find the index and push it
else {
let index = acc.findIndex(x => x[0] === curr);
if (index !== -1) {
acc[index].push(curr);
}
}
return acc;
}, []);
console.log(res);
Since you're hoping to use Lodash, you might be interested in groupBy. It returns on object, but the _.values will give you the nested array:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
let groups = _.values(_.groupBy(x))
console.log(groups)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Here's an imperative solution:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
x.sort();
var res = [];
for (const [i, n] of x.entries()) {
if (n !== x[i-1]) res.push([n]);
else res[res.length-1].push(n);
}
console.log(res);
I am trying to flatten any length of a nested array into a single array. Why it's showing array rather than array value?
function flatten(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (toString.call(arr[i]) === "[object Array]") {
res.push(flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8]));
// [1, 2, Array(2), 7, 8]
You are pushing to res the result of flatten, which is an array. Instead Array#concat the result of the inner flatten call to res, and assign the result to res.
Note: to identify an array, you can use Array#isArray.
function flatten(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8])); // [1, 2, Array(2), 7, 8]
You can use concat instead of push and reduce instead of for loop.
const flatten = data => data.reduce((r, e) => {
return r = r.concat(Array.isArray(e) ? flatten(e) : e), r
}, [])
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8]))
You can use the flat() method on the array as follows.
function flatten(arr) {
return arr.flat(10) //the number in brackets are the depth level
}
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8]));
I'm trying to write a function that finds arrays that are not common to both nested arrays. Also note the arrays will be pre-sorted.
var array1 = [ [1, 2, 3], [2, 3, 4] [5, 6, 7] ];
var array2 = [ [1, 2, 3], [2, 3, 4] [7, 8, 9] ];
For the above two arrays the function should return [5, 6, 7] and [7, 8, 9].
So far I've got:
function arrayIntersection(array1, array2) {
return array2.filter(function(values1) {
return array2.indexOf(values1) === -1;
});
};
But it doesn't seem to be working. I'm guessing the indexOf() isn't doing a compares correctly. I'm trying to avoid using ES6 or polyfills.
You can use the built in .every() and .filter() array methods to accomplish this task.
var array1 = [ [1, 2, 3], [2, 3, 4], [5, 6, 7] ];
var array2 = [ [1, 2, 3], [2, 3, 4], [7, 8, 9] ];
function compareArrays(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
} else {
return arr1.every(function(elem) {
return arr2.indexOf(elem) > -1;
});
}
}
function filterUnique(arr1, arr2) {
return arr1.filter(function(elem) {
return arr2.every(function(_elem) {
return !compareArrays(_elem, elem);
});
});
}
function filterIntersection(arr1, arr2) {
var uniqueToArr1 = filterUnique(arr1, arr2);
var uniqueToArr2 = filterUnique(arr2, arr1);
return [].concat(uniqueToArr1, uniqueToArr2);
}
console.log(filterIntersection(array1, array2));
First, you referenced the wrong array in your filter. To fix the comparison, you could turn the arrays to json. You will also need to run the filter against the second array and join the answers.:
var array1 = [ [1, 2, 3], [2, 3, 4], [5, 6, 7] ];
var array2 = [ [1, 2, 3], [2, 3, 4], [7, 8, 9] ];
function arrayIntersection(input1, input2) {
var input2NotInInput1 = input2.filter(function(values1) {
return input1.map(function(val) { return JSON.stringify(val); }).indexOf(JSON.stringify(values1)) === -1;
});
var input1NotInInput2 = input1.filter(function(values1) {
return input2.map(function(val) { return JSON.stringify(val); }).indexOf(JSON.stringify(values1)) === -1;
});
return input1NotInInput2 .concat( input2NotInInput1 );
};
console.log(arrayIntersection(array1, array2));
It's not a best option but it works
var ar1 = [
[1, 2, 3],
[2, 3, 4],
[5, 6, 7]
];
var ar2 = [
[1, 2, 3],
[2, 3, 4],
[7, 8, 9]
];
function arrayIntersection(array1, array2) {
return array2.filter(function(values1) {
return !array1.some(v => JSON.stringify(v) === JSON.stringify(values1));
});
};
var result = arrayIntersection(ar1, ar2);
console.log(result);
Using lodash, is it possible to remove one array from another while avoiding removing duplicates?
I'm currently using _.difference
// this returns [4]
_.difference([1, 1, 1, 2, 2, 2, 3, 4], [1, 2, 3])
// I want it to return [1, 1, 2, 2, 4]
This is how i would do it by pure JS
var arr1 = [1, 1, 1, 2, 2, 2, 3, 4],
arr2 = [1, 2, 3],
result = arr2.reduce((p,c) => {var idx = p.indexOf(c);
return idx === -1 ? p : (p.splice(idx,1),p)}, arr1);
console.log(result);
Based on comment from #hindmost, I used a loop.
var tempArray = [1,1,1,2,2,2,3,3,1,2]
_.each([1, 2, 3], function(value) {
tempArray.splice(tempArray.indexOf(value), 1);
});
Yes, It will return 4 Because _.difference Returns the new array of filtered values.I tried java script solution. Hope it will help you.
function keepDuplicate(array1, array2){
var occur;
var indexes = [];
_.each(array2, function(value){
_.each(array1, function(ar1value, index){
if(value === ar1value){
occur = index;
}
});
indexes.push(occur);
});
_.each(indexes, function(remove, index){
if(index === 0 ){
array1.splice(remove, 1);
}
else{
remove = remove-index;
array1.splice(remove,1);
}
});
return array1;
}
keepDuplicate([1, 1, 1, 2, 2, 2, 3, 4], [1, 2, 3])
It will Return [1, 1, 2, 2, 4]