Related
I am looping thru an array and trying to find where two elements sum to 10.
I find the correct match pairs... but for two of them the order is not retained when they are added.
I expect to get
[ [9,1], [6,4], [3,7], [7,3], [6,4], [1,9] ]
but I get
[ [9,1], [6,4], [3,7], [3,7], [6,4], [9,1] ]
i.e. => ^^^ ^^^
are different
Why do the two pairs indicated have their order backwards ?
newNums = [];
nums.forEach(num1 => {
nums.forEach(num2 => {
num1Position = nums.indexOf(num1);
num2Position = nums.indexOf(num2);
if (num1 + num2 === 10 && num2Position > num1Position ) {
newNums.push([num1, num2]);
}
})
})
return newNums;
}
result = sumTwoNumbersIsTen([9,6,3,7,3,6,4,2,0,1,9])
console.log(result); // should be [ [9,1], [6,4], [3,7], [7,3], [6,4], [1,9] ]
// but I get [ [9,1], [6,4], [3,7], [3,7], [6,4], [9,1] ]
//
You could iterate with indices and omit parts who are not valid.
BTW, it is a good idea to declare all variables.
const sumTwoNumbersIsTen = nums => {
const newNums = [];
for (let i = 0; i < nums.length - 1; i++) {
const num1 = nums[i];
for (let j = i + 1; j < nums.length; j++) {
const num2 = nums[j];
if (num1 + num2 === 10) {
newNums.push([num1, num2]);
}
}
}
return newNums;
};
console.log(sumTwoNumbersIsTen([9, 6, 3, 7, 3, 6, 4, 2, 0, 1, 9])); // [[9, 1], [6, 4], [3, 7], [7, 3], [6, 4], [1, 9]]
Because you're using the wrong positions. Instead of taking the position of the element from the current iteration, which forEach passes to your callback, you are searching for an index in the array where the value could be found. For duplicate values, this will always find the first index, not the one you want (and also it's horribly inefficient).
newNums = [];
nums.forEach((num1, num1Position) => {
nums.forEach((num2, num2Position) => {
if (num1 + num2 === 10 && num2Position > num1Position ) {
newNums.push([num1, num2]);
}
})
})
The problem is that there are (for example) two 9s in the array, and .indexOf only finds the index of the first occurence.
You can solve this by not using indexOf and instead exploiting that the callback to forEach can take a second parameter which is the element's index:
function sumTwoNumbersIsTen(nums) {
newNums = [];
nums.forEach((num1, num1Position) => {
nums.forEach((num2, num2Position) => {
if (num1 + num2 === 10 && num2Position > num1Position ) {
newNums.push([num1, num2]);
}
})
})
return newNums;
}
result = sumTwoNumbersIsTen([9,6,3,7,3,6,4,2,0,1,9])
console.log(result);
I have some arrays like [1,5], [3,6], [2,8],[19,13], [12,15]. When i pass two arrays in the function output will be [1,6], [2,19],[12,15]
i want to remove overlapping numbers from 2 arrays . like on fist and second array 5 and 3 will be overlap between 1 to 6.
I believe this is what you want (you get the min of the first array and the max of the second array):
function removeOverlap(arr1, arr2) {
if (arr1 === undefined) {
return arr2;
}
if (arr2 === undefined) {
return arr1;
}
return [Math.min.apply(null, arr1), Math.max.apply(null, arr2)];
}
// Sample:
var myArrays = [[1,5], [3,6], [2,8], [19,13], [12,15]];
for (var i = 0; i < myArrays.length; i = i + 2) {
console.log(removeOverlap(myArrays[i], myArrays[i + 1]));
}
EDIT: answer with multiple parameters as you requested in your comment:
We could use rest parameters in the answer below, but I will use the arguments object for compatibility with Internet Explorer. If this is not a requirement you can adapt the solution to use the first.
function removeOverlap(arr1, arr2) {
// Converting the arguments object to array:
var argsArray = Array.prototype.slice.call(arguments);
// Removing undefined:
argsArray = argsArray.filter(function(el) {
return el != undefined;
});
// Alternative (not compatible with Internet Explorer):
//argsArray = argsArray.filter(el => el);
// We're looking for the min and max numbers, let's merge the arrays
// e.g. transform [[1, 5], [3, 6], [2, 8]] into [1, 5, 3, 6, 2, 8]
var merged = [].concat.apply([], argsArray);
// Alternative, but it is not compatible with Internet Explorer:
//var merged = Array.flat(argsArray);
return [Math.min.apply(null, merged), Math.max.apply(null, merged)];
}
// Sample:
var myArrays = [[1,5], [3,6], [2,8], [19,13], [12,15]];
for (var i = 0; i < myArrays.length; i = i + 2) {
console.log(removeOverlap(myArrays[i], myArrays[i + 1]));
}
console.log(removeOverlap(myArrays[0], myArrays[1], myArrays[2]));
This can easily be accomplished my finding the min of the current and max of the next item.
let initial = [ [1, 5], [3, 6], [2, 8], [19, 13], [12, 15] ]
let expected = [ [1, 6], [2, 19], [12, 15] ]
let actual = calculateOverlaps(initial);
console.log(JSON.stringify(actual) === JSON.stringify(expected)); // true
function calculateOverlaps(arr) {
let result = [];
for (let i = 0; i < arr.length; i+=2) {
if (i >= arr.length - 1) {
result.push(arr[i]); // If the array has an odd size, get last item
} else {
let curr = arr[i];
let next = arr[i + 1];
result.push([ Math.min(...curr), Math.max(...next) ]);
}
}
return result;
}
Here is a more code-golf oriented function:
const calculateOverlaps1 = (arr) => arr.reduce((r, e, i, a) =>
(i % 2 === 0)
? r.concat([
(i < a.length - 1)
? [ Math.min(...e), Math.max(...a[i+1]) ]
: e
])
: r, []);
And even smaller, at just 101 bytes.
f=a=>a.reduce((r,e,i)=>i%2===0?r.concat([i<a.length-1?[Math.min(...e),Math.max(...a[i+1])]:e]):r,[]);
I have an array of object where I want to create every unique combination of objects as its own array. The combinations also need to include a different number of elements and should work regardless of the elements provided. To simplify the problem let's say we have the following array.
let arr = [1, 2, 3];
The result in this situation would be the following:
[1]
[2]
[3]
[1, 2]
[1, 3]
[2, 3]
[1, 2, 3]
I have looked for a solution and have found an approach using cartesian products, but this doesn't really seem to apply for this case since i need unique combinations and no replicates. How can I a approach this problem with Javascript?
You could take a recursive approach and return an array of items.
function combinations(array) {
function iter(index, temp = []) {
if (!index--) return;
iter(index, temp);
result.push(temp = [array[index], ...temp]);
iter(index, temp);
}
var result = [];
iter(array.length);
return result;
}
combinations([1, 2, 3]).forEach(a => console.log(a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This can be defined recursively in pseudo-Javascript:
function combos(arr) {
if arr is empty
return arr;
else {
result = [];
// for every combination from the rest of the list
for x in combos( arr.slice(1) ) {
// get that combination w/o arr[0]
result.push( x );
x.push( arr[0] );
// … and the combination w/ arr[0]
result.push( x );
}
}
}
I managed to create a solution on my own. I created two helper functions for making the problem easier. The first one is just a function for switching array indexes and the second one is a recursive function that let's me remove an element at each recursive call and sums the result to its own array.
By iterating for every element i can get all the n-length combinations for the array. Then I remove the first element and repeat the procedure until i am out of elements. This will give me all the solutions, but they will have duplicates.
By sorting them ascending and converting them to a string i can create a Set out of them, which will create unique strings. The last step is to remove the duplicates and I end up with all the combinations.
let arr = [1, 2, 3];
let result = [];
while (arr.length !== 0) {
for (let i = 0; i < arr.length; i++) {
result = [...result, ...levelCombo(arr)];
arr = switchIndex(arr, 0, i);
}
arr = arr.slice(1);
}
result = result.map(el => JSON.stringify(el.sort()));
let uniqueResult = [...new Set(result)].map(el => JSON.parse(el));
console.log(uniqueResult);
function switchIndex(arr, a, b) {
let val1 = arr[a];
let val2 = arr[b];
arr[a] = val2;
arr[b] = val1;
return arr;
}
function levelCombo(arr) {
let result = [];
if (arr.length === 0) {
return [];
}
for (let i = 0; i < arr.length; i++) {
result.push(arr[i]);
}
result = [result, ...levelCombo(arr.slice(1))];
return result;
}
For the input [1, 2, 3] the printed result will be the following:
[
[ 1, 2, 3 ],
[ 2, 3 ],
[ 3 ],
[ 1, 3 ],
[ 1, 2 ],
[ 2 ],
[ 1 ]
]
I was trying to write a algorithm in javascript that returns all the possible 3 digit numbers numbers from a given array of length 6
For Example
var arr = [1, 2, 3, 4, 5, 6];
I have already got the combinations with the same sets of numbers in different positions in the 2D array.
(The code which I took the help of)
If I have the same numbers in different combinations then I would like to remove them form the array. like I have [1, 2, 3] at index i in the array comtaining all the possible combinations then I would like to remove other combination with the same numbers like [2, 1, 3], [1, 3, 2] and so on..
Note the array also contains numbers repeated like [3, 3, 3], [2, 2, 2], [3, 2, 3] and so on
I expect an 2d array which has the values : [[1,2,3],[1,2,4],[1,2,5],[1,2,6],[1,3,4]] and so on (24 possibilities)
Is there any way to do this?
Extending the answer you linked, just filter out the results with the help of a Set.
Sort an individual result, convert them into a String using join(), check if it's present in set or not, and if not, then store them in the final result.
function cartesian_product(xs, ys) {
var result = [];
for (var i = 0; i < xs.length; i++) {
for (var j = 0; j < ys.length; j++) {
// transform [ [1, 2], 3 ] => [ 1, 2, 3 ] and append it to result []
result.push([].concat.apply([], [xs[i], ys[j]]));
}
}
return result;
}
function cartesian_power(xs, n) {
var result = xs;
for (var i = 1; i < n; i++) {
result = cartesian_product(result, xs)
}
return result;
}
function unique_cartesian_power(xs, n) {
var result = cartesian_power(xs, n);
var unique_result = [];
const set = new Set();
result.forEach(function(value) {
var representation = value.sort().join(' ');
if (!set.has(representation)) {
set.add(representation);
unique_result.push(value);
}
});
return unique_result;
}
console.log(unique_cartesian_power([1, 2, 3, 4, 5, 6], 3));
const arr = [1, 2, 3, 4, 5, 6];
const result = arr.reduce((a, v) => arr.reduce((a, v2) => {
arr.reduce((a, v3) => {
const current = [v, v2, v3].sort().join(",");
!a.find(_ => _.sort().join() === current) && a.push([v, v2, v3]);
return a;
}, a);
return a;
}, a), []);
console.log(result.length);
console.log(...result.map(JSON.stringify));
You could take an iterative and recursive approach by sorting the index and a temporary array for the collected values.
Because of the nature of going upwards with the index, no duplicate set is created.
function getCombination(array, length) {
function iter(index, right) {
if (right.length === length) return result.push(right);
if (index === array.length) return;
for (let i = index, l = array.length - length + right.length + 1; i < l; i++) {
iter(i + 1, [...right, array[i]]);
}
}
var result = [];
iter(0, []);
return result;
}
var array = [1, 2, 3, 4, 5, 6],
result = getCombination(array, 3);
console.log(result.length);
result.forEach(a => console.log(...a));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is a good example, that it is usually worthwhile not asking for a specific answer for a generic problem shown with a specific question; however as you've requested - if you really have the above constraints which kind of don't make much sense to me, you could do it like that:
function combine(firstDigits, secondDigits, thirdDigits) {
let result = [];
firstDigits.forEach(firstDigit => {
// combine with all secondDigitPermutations
secondDigits.forEach(secondDigit => {
// combine with all thirdDigitPermutations
thirdDigits.forEach(thirdDigit => {
result.push([firstDigit, secondDigit, thirdDigit])
})
})
});
// now we have all permutations and simply need to filter them
// [1,2,3] is the same as [2,3,1]; so we need to sort them
// and check them for equality (by using a hash) and memoize them
// [1,2,3] => '123'
function hashCombination(combination) {
return combination.join('ಠ_ಠ');
}
return result
// sort individual combinations to make them equal
.map(combination => combination.sort())
.reduce((acc, currentCombination) => {
// transform the currentCombination into a "hash"
let hash = hashCombination(currentCombination);
// and look it up; if it is not there, add it to cache and result
if (!(hash in acc.cache)) {
acc.cache[hash] = true;
acc.result.push(currentCombination);
}
return acc;
}, {result: [], cache: {}})
.result;
}
console.log(combine([1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]).length);
console.log(...combine([1,2,3,4,5,6],[1,2,3,4,5,6],[1,2,3,4,5,6]).map(JSON.stringify));
This does not include some super-clever assumptions about some index, but it does abuse the fact, that it's all about numbers. It is deliberately using no recursion, because this would easily explode, if the amount of combinations is going to be bigger and because recursion in itself is not very readable.
For a real world problem™ - you'd employ a somewhat similar strategy though; generating all combinations and then filter them. Doing both at the same time, is an exercise left for the astute reader. For finding combinations, that look different, but are considered to be the same you'd also use some kind of hashing and memoizing.
let arr1 = [1,2,3,4,5,6];
function getCombination(arr){
let arr2 = [];
for(let i=0; i<arr.length; i++){
for(let j=i; j<arr.length; j++){
for(let k=j; k<arr.length; k++){
arr2.push([arr[i],arr[j],arr[k]]);
}
}
}
return arr2;
}
console.log(getCombination(arr1));
Have an array arr =
[ [1,2] , [5,1], [23,24], [3,4], [22,23], [2,3]]
output needed = [[5,1,2,3,4],[22,23,24]]
tried using concat, reduce methods of array in javascript but could not achieve the desired result - any ideas?
I'm going to start by saying the code example and description is not very clear, but I'll take a shot...
It seems you have 3 requirements:
Flatten the original array.
Filter out duplicates.
Group values (somehow?) within the flattened array.
The first 2 tasks on the list can be accomplished using reduce, concat, filter and indexOf methods.
var multiArray = [ [1,2] , [5,1], [23,24], [3,4], [22,23], [2,3] ];
var flattened = multiArray.reduce(function (prev, curr) {
return prev.concat(curr);
}, []);
var unique = flattened.filter(function (element, index, array) {
return array.indexOf(element) === index;
});
However, I wont be able to give you an example for that last task until you make it clear how you're hoping to have these values grouped within the flattened array.
I'll update my original answer once clarified.
This is another solution yet i believe i can make it with less code and more functional. I don't enjoy using forEach() or flags like reduced much. This one recursively encodes the array items until there is nothing left to encode. Later I will give it another try to make it look more sleek.
var rawarr = [[1,2], [5,1], [23,24], [3,4], [22,23], [2,3]],
encodarr = (arr) => {
var reduced = false;
arr.forEach((c,i,a) => {
var sa = a.slice(i+1),
j = sa.findIndex(f => c[0] == f[f.length-1] || c[c.length-1] == f[0]);
arr[i] = !!~j ? c[0] == sa[j][sa[j].length-1] ? (reduced = true, a.splice(i+j+1,1)[0].concat(c.slice(1)))
: (reduced = true, c.slice(0,-1).concat(a.splice(i+j+1,1)[0]))
: c;
return arr;
});
return reduced ? encodarr(arr) : arr;
};
document.write("<pre>" + JSON.stringify(encodarr(rawarr)) + "</pre>");
Basically this problem can be solved with more loops and only one array (A) or with an object as reference and only one loop (B).
A
An in situ proposal with no object, but with more loops. It checks every array with the path information with each other. If a match is found, the two arrays are
var data = [[1, 2], [5, 1], [23, 24], [3, 4], [22, 23], [2, 3], [4, 5]],
result = function (data) {
function first(a) { return a[0]; }
function last(a) { return a[a.length - 1]; }
var i = 0, j, t;
outer: while (i < data.length - 1) {
j = i + 1;
while (j < data.length) {
t = data.splice(j, 1)[0];
if (first(data[i]) === last(t)) {
t.pop();
data[i] = t.concat(data[i]);
i = 0;
continue outer;
}
if (last(data[i]) === first(t)) {
t.shift();
data[i] = data[i].concat(t);
i = 0;
continue outer;
}
data.push(t);
j++;
}
i++
}
return data;
}(data);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
B
This is a single loop proposal which takes all parts and appends them if possible. Later all start arrays are returned as result.
var data = [[1, 2], [5, 1], [23, 24], [3, 4], [22, 23], [2, 3], [4, 5]],
result = function (data) {
var o = { start: {}, end: {} };
data.forEach(function (a) {
var temp;
if (o.end[a[0]]) {
if (o.start[a[1]] && a[0] !== o.start[a[1]][o.start[a[1]].length - 1] && a[1] !== o.end[a[0]][0]) {
temp = o.end[a[0]].concat(o.start[a[1]]);
o.start[temp[0]] = temp;
o.end[temp[temp.length - 1]] = temp;
delete o.start[a[1]];
} else {
o.end[a[1]] = o.end[a[0]];
o.end[a[1]].push(a[1]);
}
delete o.end[a[0]];
return;
}
if (o.start[a[1]]) {
o.start[a[0]] = o.start[a[1]];
o.start[a[0]].unshift(a[0]);
delete o.start[a[1]];
return;
}
temp = a.slice();
o.start[a[0]] = temp;
o.end[a[1]] = temp;
});
return Object.keys(o.start).map(function (k) { return o.start[k]; });
}(data);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');