Finding all combination sequences from array in JS - javascript

Disclaimer: I know part of this question has been asked and answered here before and yes, they have helped me get to this point so far.
Let's say I have an array that contains 2 elements and I want to find ALL possible combinations that could be made up of these elements. The order of the sets does not matter.
var myArr = ['a','b'];
Desired result
var result = [ [a], [a,b], [b], [b,a] ]
At first I thought I was looking for a power set however I do not want a null set and I want to treat [a,b] and [b,a] as unique sequences NOT as equals. More info about sets, null set, and equal sets here.
So far I have written this function that will recursively loop through my array, create new arrays for each possible combinations and push them into a results array.
function getCombinations() {
var myArr = ['a','b'],
result = [];
var recurFn = function(prefix, myArr) {
for (var i = 0; i < myArr.length; i++) {
var newArray = prefix !== '' ? [prefix, myArr[i]] : [myArr[i]];
result.push(newArray);
recurFn(prefix + myArr[i], myArr.slice(i + 1));
}
}
recurFn('', myArr);
console.log(result); //[[a], [a,b], [b]]
}
Here is a fiddle with my above code.
Currently I am only returning 3 possible combinations [a], [a,b], [b], how can I edit my code so that I am returning [a], [a,b], [b], [b,a].
Thanks!

Can you make two arrays in reverse order:
var myArr = ['a','b']
var myArr2 = ['b','a']
var recurFn = function(prefix, myArr) {
for (var i = 0; i < myArr.length; i++) {
var newArray = prefix !== '' ? [prefix, myArr[i]] : [myArr[i]];
result.push(newArray);
recurFn(prefix + myArr[i], myArr.slice(i + 1));
}
for (var i = 0; i < myArr2.length; i++) {
var newArray2 = prefix !== '' ? [prefix, myArr2[i]] : [myArr2[i]];
result.push(newArray2);
recurFn(prefix + myArr2[i], myArr2.slice(i + 1));
}
newArray.concat(newArray2);
newArray.unique();
}

Try this, works for all array sizes:
jsfiddle: https://jsfiddle.net/fcwa3cz5/2/
console.log(allArrCombi(['a','b','c']));
function allArrCombi(arr){
var hash={};
var res=[];
arr.sort();
var len=Math.pow(2, arr.length);
for (var i=1;i<len;i++){
var lineRes=[];
for (var innerPos=0;innerPos < arr.length;innerPos++){
var mask = 1 << innerPos;
if (mask & i){
lineRes.push(arr[innerPos]);
}
}
do{
if (!hash[arr.join("-")]){ // did we have this combinatin already
res.push(lineRes.slice())
}
}while(nextPermutation(lineRes))
}
return res;
}
function nextPermutation(array) {
var i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i])
i--;
if (i <= 0)
return false;
var j = array.length - 1;
while (array[j] <= array[i - 1])
j--;
var temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return true;
}

Related

I want to make this bubble sort function work but it gives me Maximum call stack size exceeded

function bubbleSort(arr) {
var temp = arr.slice(0)
for (var i = 0; i < arr.length; i ++) {
if (arr[i + 1] < arr[i]) {
var temp_1 = arr[i+1]
var temp_2 = arr[i]
arr[i] = temp_1
arr[i+1] = temp_2
}
}
if (temp != arr) {
return bubbleSort(arr)
}
return arr
}
console.log(bubbleSort([2,1,5,4,10,7,6,9,3,8]))
I'm not looking at the algorithm because I think you have it right. You're problem is the comparison between arrays. Try use this function
JSON.stringify(temp) !== JSON.stringify(array);
What's happening here is that temp != array always returns true, you can see it by adding
console.log(temp !== array)
before the comparison.
Explaination: JSON#stringify compares two strings obtained from the array. Another way to achieve comparison is comparing the lenght and the equality of all the items one by one. If you use "!=" operator you'll always get nothing but "true" as the two arrays are two different instances of Object
Complete code
function bubbleSort(arr) {
var temp = arr.slice(0);
for (var i = 0; i < arr.length; i ++) {
if (arr[i + 1] < arr[i]) {
var temp_1 = arr[i+1];
var temp_2 = arr[i];
arr[i] = temp_1;
arr[i+1] = temp_2;
}
}
if (JSON.stringify(temp) !== JSON.stringify(arr)) {
return bubbleSort(arr);
}
return arr
}
Operators == and != are comparing references, so they will always consider two arrays as different (unless you comparing same instance). Check ['a'] == ['a']: it will be false.
You could use flag to indicate changes was occurred:
function bubbleSort(arr) {
var temp = arr.slice(0)
var changed = false
for (var i = 0; i < arr.length; i ++) {
if (arr[i + 1] < arr[i]) {
changed = true
var temp_1 = arr[i+1]
var temp_2 = arr[i]
arr[i] = temp_1
arr[i+1] = temp_2
}
}
if (changed) {
return bubbleSort(arr)
}
return arr
}
As soon as you don't know length of the input array and how close it is to sorted state, you still might fall into same problem in some cases, so it's better to replace recursion by loop:
function bubbleSort(arr) {
var changed = false
do {
var temp = arr.slice(0)
changed = false
for (var i = 0; i < arr.length; i ++) {
if (arr[i + 1] < arr[i]) {
changed = true
var temp_1 = arr[i+1]
var temp_2 = arr[i]
arr[i] = temp_1
arr[i+1] = temp_2
}
}
} while (changed);
return arr
}

Issue while making a copy of 2D Array

My target here is to find 'N' for a 2D Array.
'N' = sum of corner elements * sum of non corner elements.
For 'N' calculation I change String & Boolean elements to their ASCII, 1 or 0 respectively. But my original array gets altered in this process.
Can't understand why?
function findN(arr) {
var temp = [...arr]
// first we change all elements to numbers
for (let i = 0; i < temp.length; i++) {
for (let j = 0; j < temp.length; j++) {
if (typeof temp[i][j] == 'string') {
temp[i][j] = temp[i][j].charCodeAt()
} else if (temp[i][j] == true) {
temp[i][j] = 1
} else if (temp[i][j] == false) {
temp[i][j] = 0
}
}
}
// N calculation starts here
let r = temp.length // rows
let c = temp[0].length // columns
var corner_Sum =
temp[0][0] + temp[0][c - 1] + temp[r - 1][0] + temp[r - 1][c - 1]
var total_Sum = 0
for (let i = 0; i < temp.length; i++) {
for (let j = 0; j < temp.length; j++) {
total_Sum = total_Sum + arr[i][j]
}
}
var N = corner_Sum * (total_Sum - corner_Sum)
return N
}
findN() ends here. It should return 'N', without altering the original array. As all calculations were done on temp array. But that's not the case.
Your problem is because arr is an array of arrays; when you copy it using
temp = [...arr]
temp becomes an array of references to the same subarrays in arr. Thus when you change a value in temp it changes the corresponding value in arr. You can see this in a simple example:
let arr = [[1, 2], [3, 4]];
let temp = [...arr];
temp[0][1] = 6;
console.log(arr);
console.log(temp);
To work around this, use a deep copy such as those described here or here. For example, if arr is at most 2-dimensional, you can nest the spread operator:
let arr = [[1, 2], [3, 4]];
let temp = [...arr.map(a => [...a])];
temp[0][1] = 6;
console.log(arr);
console.log(temp);

adding values that meet a certain condition javascript

I have an array of strings array_strings and I want to get the maximum length of x consecutive values from the list and return a string. I have tried with this code but, its not working.
var myArr = ['we', 'make', 'the', 'best', 'dishes', 'in', 'cooking', 'class'];
x = 2;
function myFunc(array_strings, x) {
// your code
let val = '',
y = 0;
array_strings.sort((a, b) => {
return a.length < b.length
});
if (array_strings.length > 0) {
while (x) {
val += array_strings[y];
y++;
x--;
}
}
return val;
}
console.log(myFunc(myArr, x))
// expected output 'cookingclass'
on sorting, I cannot satisfy the consecutive order. Where am I going wrong?
To keep it simple, first get all possible values for x consecutive items.
function longestConsecutives(arr, x) {
var consecutives = [];
for (var i=0; i<arr.length-x; i++)
consecutives.push(arr.slice(i, x).join(''));
and then search the one with maximum length amongst them:
var longest = consecutives[0];
for (var i=1; i<consecutives.length; i++)
if (consecutives[i].length > longest.length)
longest = consecutives[i];
return longest;
}
There is also a more efficient approach to find the result, have a look at this for inspiration.
I don't think there's any reason to sort for this. You can just move a sliding window of x length over the array and keep track of the longest sequence you've seen:
let array_strings = ['we', 'make', 'the', 'best', 'dishes', 'in', 'cooking', 'class']
function findMax(array_strings, x){
let max_index = 0, max_length = 0
for (let i= 0; i < array_strings.length - x + 1; i++){
let length = array_strings.slice(i, i+x).reduce((l, c) => l + c.length, 0)
if (length > max_length) {
max_index = i,
max_length = length
}
}
return array_strings.slice(max_index, max_index + x)
}
console.log(findMax(array_strings,2))
console.log(findMax(array_strings,3))
console.log(findMax(array_strings,4))
Rolling sum O(n) solution:
function findLongestConsec(arr, l) {
var curSum = array_strings.slice(0, l).map(ele => ele.length).reduce((a, b) => a+b);
var curMax = curSum;
var curMaxIndex = 0;
for (var i = 1; i < arr.length - l + 1; i++) {
curSum = curMax - arr[i-1].length + arr[i+l-1].length;
if (curSum > curMax) {
curMax = curSum;
curMaxIndex = i;
}
}
return arr.slice(curMaxIndex, curMaxIndex + l).join('');
}
The previous solutions all involve string concatenation. I don't think it's worth doing it every time. We just have to keep track of the starting index of the longest subarray.
Try this:
arr = ['we', 'make', 'the', 'best', 'dishes', 'in', 'cooking', 'class']
x = 2
var sorting = function (array_strings, items) {
// your code
let val = '', y = 0;
const sort = array_strings.sort((a, b) => a.length < b.length);
console.log({sort});
if (arr.length > 0){
while (items){
val += array_strings[y];
y++;
items--;
}
}
return val;
}
var s = sorting(arr,x);
console.log({s});

Infinity loop with generating random numbers?

I'm working on a script that creates random mathematical problems (simple questions). The problem is that there seems to be an infinite loop, and I can't figure out where or how my script can run without this part of the code.
https://codepen.io/abooo/pen/GyJKwP?editors=1010
var arr = [];
var lastArr = [];
while(lastArr.length<122){
arr.push('<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'=');
lastArr=removeDuplicates(arr);
}
document.write(lastArr.join(' '));
alert(arr.length);
function removeDuplicates(arr){
let unique_array = []
for(let i = 0;i < arr.length; i++){
if(unique_array.indexOf(arr[i]) == -1){
unique_array.push(arr[i])
}
}
return unique_array
}
This is the working snippet without any infinity loop.
var arr = [];
while(arr.length < 121){
var randValue = '<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'='
arr.push();
// Check duplicate elements before push
if ( arr.indexOf(randValue) == -1 ) arr.push(randValue);
}
document.write(arr.join(' '));
alert(arr.length);
It looks like you are trying to shuffle every possible outcome of adding two numbers from 0 to 10. Why not do that, rather than your attempt of "throw missiles into pidgeonholes and hope for the best"?
function generateArray(maxA, maxB) {
var arr = [],
a, b;
for (a = 0; a <= maxA; a++) {
for (b = 0; b <= maxB; b++) {
arr.push([a, b]);
}
}
return arr;
}
function shuffleArray(arr) {
// simple Fisher-Yates shuffle, modifies original array
var l = arr.length,
i, j, t;
for (i = l - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
function outputArray(arr) {
var i, l = arr.length;
for (i = 0; i < l; i++) {
document.write("<br />" + arr[i][0] + " + " + arr[i][1] + " = ");
}
}
var arr = generateArray(10, 10);
shuffleArray(arr);
outputArray(arr);
The line Math.round(Math.random() * 10) will give you 11 possible outcomes (from 0 to 10). That means there are 11*11 non-duplicates lastArr can hold.
As mentioned in the comments, it does not only take a long time for every possibility to occur, it is also impossible for lastArr to be longer than 121 (11*11), which means your loop cannot end, due to the condition while(lastArr.length<122).
Besides that there are better ways to achieve the desired result, changing your code to this will make it work:
var arr = [];
var lastArr = [];
while(lastArr.length<121){ // Here I change 122 to 121
arr.push('<br>'+Math.round(Math.random() * 10)+'+'+Math.round(Math.random() * 10)+'=');
lastArr=removeDuplicates(arr);
}
document.write(lastArr.join(' '));
alert(arr.length);
function removeDuplicates(arr){
let unique_array = []
for(let i = 0;i < arr.length; i++){
if(unique_array.indexOf(arr[i]) == -1){
unique_array.push(arr[i])
}
}
return unique_array
}

Pair of elements from a specified array whose sum equals a specific target number

I am in mid of my JavaScript session. Find this code in my coding exercise. I understand the logic but I didn't get this map[nums[x]] condition.
function twoSum(nums, target_num) {
var map = [];
var indexnum = [];
for (var x = 0; x < nums.length; x++)
{
if (map[nums[x]] != null)
// what they meant by map[nums[x]]
{
index = map[nums[x]];
indexnum[0] = index+1;
indexnum[1] = x+1;
break;
}
else
{
map[target_num - nums[x]] = x;
}
}
return indexnum;
}
console.log(twoSum([10,20,10,40,50,60,70],50));
I am trying to get the Pair of elements from a specified array whose sum equals a specific target number. I have written below code.
function arraypair(array,sum){
for (i = 0;i < array.length;i++) {
var first = array[i];
for (j = i + 1;j < array.length;j++) {
var second = array[j];
if ((first + second) == sum) {
alert('First: ' + first + ' Second ' + second + ' SUM ' + sum);
console.log('First: ' + first + ' Second ' + second);
}
}
}
}
var a = [2, 4, 3, 5, 6, -2, 4, 7, 8, 9];
arraypair(a,7);
Is there any optimized way than above two solutions? Can some one explain the first solution what exactly map[nums[x]] this condition points to?
Using HashMap approach using time complexity approx O(n),below is the following code:
let twoSum = (array, sum) => {
let hashMap = {},
results = []
for (let i = 0; i < array.length; i++){
if (hashMap[array[i]]){
results.push([hashMap[array[i]], array[i]])
}else{
hashMap[sum - array[i]] = array[i];
}
}
return results;
}
console.log(twoSum([10,20,10,40,50,60,70,30],50));
result:
{[10, 40],[20, 30]}
I think the code is self explanatory ,even if you want help to understand it,let me know.I will be happy enough to for its explanation.
Hope it helps..
that map value you're seeing is a lookup table and that twoSum method has implemented what's called Dynamic Programming
In Dynamic Programming, you store values of your computations which you can re-use later on to find the solution.
Lets investigate how it works to better understand it:
twoSum([10,20,40,50,60,70], 50)
//I removed one of the duplicate 10s to make the example simpler
In iteration 0:
value is 10. Our target number is 50. When I see the number 10 in index 0, I make a note that if I ever find a 40 (50 - 10 = 40) in this list, then I can find its pair in index 0.
So in our map, 40 points to 0.
In iteration 2:
value is 40. I look at map my map to see I previously found a pair for 40.
map[nums[x]] (which is the same as map[40]) will return 0.
That means I have a pair for 40 at index 0.
0 and 2 make a pair.
Does that make any sense now?
Unlike in your solution where you have 2 nested loops, you can store previously computed values. This will save you processing time, but waste more space in the memory (because the lookup table will be needing the memory)
Also since you're writing this in javascript, your map can be an object instead of an array. It'll also make debugging a lot easier ;)
function twoSum(arr, S) {
const sum = [];
for(let i = 0; i< arr.length; i++) {
for(let j = i+1; j < arr.length; j++) {
if(S == arr[i] + arr[j]) sum.push([arr[i],arr[j]])
}
}
return sum
}
Brute Force not best way to solve but it works.
Please try the below code. It will give you all the unique pairs whose sum will be equal to the targetSum. It performs the binary search so will be better in performance. The time complexity of this solution is O(NLogN)
((arr,targetSum) => {
if ((arr && arr.length === 0) || targetSum === undefined) {
return false;
} else {
for (let x = 0; x <=arr.length -1; x++) {
let partnerInPair = targetSum - arr[x];
let start = x+1;
let end = (arr.length) - 2;
while(start <= end) {
let mid = parseInt(((start + end)/2));
if (arr[mid] === partnerInPair) {
console.log(`Pairs are ${arr[x]} and ${arr[mid]} `);
break;
} else if(partnerInPair < arr[mid]) {
end = mid - 1;
} else if(partnerInPair > arr[mid]) {
start = mid + 1;
}
}
};
};
})([0,1,2,3,4,5,6,7,8,9], 10)
function twoSum(arr, target) {
let res = [];
let indexes = [];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (target === arr[i] + arr[j] && !indexes.includes(i) && !indexes.includes(j)) {
res.push([arr[i], arr[j]]);
indexes.push(i);
indexes.push(j);
}
}
}
return res;
}
console.log('Result - ',
twoSum([1,2,3,4,5,6,6,6,6,6,6,6,6,6,7,8,9,10], 12)
);
Brute force.
const findTwoNum = ((arr, value) => {
let result = [];
for(let i= 0; i< arr.length-1; i++) {
if(arr[i] > value) {
continue;
}
if(arr.includes(value-arr[i])) {
result.push(arr[i]);
result.push(value-arr[i]);
break;;
}
}
return result;
});
let arr = [20,10,40,50,60,70,30];
const value = 120;
console.log(findTwoNum(arr, value));
OUTPUT : Array [50, 70]
function twoSum(arr){
let constant = 17;
for(let i=0;i<arr.length-2;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[i]+arr[j] === constant){
console.log(arr[i],arr[j]);
}
}
}
}
let myArr = [2, 4, 3, 5, 7, 8, 9];
function getPair(arr, targetNum) {
for (let i = 0; i < arr.length; i++) {
let cNum = arr[i]; //my current number
for (let j = i; j < arr.length; j++) {
if (cNum !== arr[j] && cNum + arr[j] === targetNum) {
let pair = {};
pair.key1 = cNum;
pair.key2 = arr[j];
console.log(pair);
}
}
}
}
getPair(myArr, 7)
let sumArray = (arr,target) => {
let ar = []
arr.forEach((element,index) => {
console.log(index);
arr.forEach((element2, index2) => {
if( (index2 > index) && (element + element2 == target)){
ar.push({element, element2})
}
});
});
return ar
}
console.log(sumArray([8, 7, 2, 5, 3, 1],10))
Use {} hash object for storing and fast lookups.
Use simple for loop so you can return as soon as you find the right combo; array methods like .forEach() have to finish iterating no matter what.
And make sure you handle edges cases like this: twoSum([1,2,3,4], 8)---that should return undefined, but if you don't check for !== i (see below), you would erroneously return [4,4]. Think about why that is...
function twoSum(nums, target) {
const lookup = {};
for (let i = 0; i < nums.length; i++) {
const n = nums[i];
if (lookup[n] === undefined) {//lookup n; seen it before?
lookup[n] = i; //no, so add to dictionary with index as value
}
//seen target - n before? if so, is it different than n?
if (lookup[target - n] !== undefined && lookup[target - n] !== i) {
return [target - n, n];//yep, so we return our answer!
}
}
return undefined;//didn't find anything, so return undefined
}
We can fix this with simple JS object as well.
const twoSum = (arr, num) => {
let obj = {};
let res = [];
arr.map(item => {
let com = num - item;
if (obj[com]) {
res.push([obj[com], item]);
} else {
obj[item] = item;
}
});
return res;
};
console.log(twoSum([2, 3, 2, 5, 4, 9, 6, 8, 8, 7], 10));
// Output: [ [ 4, 6 ], [ 2, 8 ], [ 2, 8 ], [ 3, 7 ] ]
Solution In Java
Solution 1
public static int[] twoNumberSum(int[] array, int targetSum) {
for(int i=0;i<array.length;i++){
int first=array[i];
for(int j=i+1;j<array.length;j++){
int second=array[j];
if(first+second==targetSum){
return new int[]{first,second};
}
}
}
return new int[0];
}
Solution 2
public static int[] twoNumberSum(int[] array, int targetSum) {
Set<Integer> nums=new HashSet<Integer>();
for(int num:array){
int pmatch=targetSum-num;
if(nums.contains(pmatch)){
return new int[]{pmatch,num};
}else{
nums.add(num);
}
}
return new int[0];
}
Solution 3
public static int[] twoNumberSum(int[] array, int targetSum) {
Arrays.sort(array);
int left=0;
int right=array.length-1;
while(left<right){
int currentSum=array[left]+array[right];
if(currentSum==targetSum){
return new int[]{array[left],array[right]};
}else if(currentSum<targetSum){
left++;
}else if(currentSum>targetSum){
right--;
}
}
return new int[0];
}
function findPairOfNumbers(arr, targetSum) {
var low = 0, high = arr.length - 1, sum, result = [];
while(low < high) {
sum = arr[low] + arr[high];
if(sum < targetSum)
low++;
else if(sum > targetSum)
high--;
else if(sum === targetSum) {
result.push({val1: arr[low], val2: arr[high]});
high--;
}
}
return (result || false);
}
var pairs = findPairOfNumbers([1,2,3,4,4,5], 8);
if(pairs.length) {
console.log(pairs);
} else {
console.log("No pair of numbers found that sums to " + 8);
}
Simple Solution would be in javascript is:
var arr = [7,5,10,-5,9,14,45,77,5,3];
var arrLen = arr.length;
var sum = 15;
function findSumOfArrayInGiven (arr, arrLen, sum){
var left = 0;
var right = arrLen - 1;
// Sort Array in Ascending Order
arr = arr.sort(function(a, b) {
return a - b;
})
// Iterate Over
while(left < right){
if(arr[left] + arr[right] === sum){
return {
res : true,
matchNum: arr[left] + ' + ' + arr[right]
};
}else if(arr[left] + arr[right] < sum){
left++;
}else{
right--;
}
}
return 0;
}
var resp = findSumOfArrayInGiven (arr, arrLen, sum);
// Display Desired output
if(resp.res === true){
console.log('Matching Numbers are: ' + resp.matchNum +' = '+ sum);
}else{
console.log('There are no matching numbers of given sum');
}
Runtime test JSBin: https://jsbin.com/vuhitudebi/edit?js,console
Runtime test JSFiddle: https://jsfiddle.net/arbaazshaikh919/de0amjxt/4/
function sumOfTwo(array, sumNumber) {
for (i of array) {
for (j of array) {
if (i + j === sumNumber) {
console.log([i, j])
}
}
}
}
sumOfTwo([1, 2, 3], 4)
function twoSum(args , total) {
let obj = [];
let a = args.length;
for(let i = 0 ; i < a ; i++){
for(let j = 0; j < a ; j++){
if(args[i] + args[j] == total) {
obj.push([args[i] , args[j]])
}
}
}
console.log(obj)}
twoSum([10,20,10,40,50,60,70,30],60);
/* */

Categories

Resources