I’m trying to generate all valid combinations of numbers from an array of digits. Let’s assume we have the following:
let arr = [1, 2, 9, 4, 7];
We need to output something like this:
1 2 9 4 7
1 2 9 47
1 2 94 7
1 2 947
1 29 4 7
1 29 47
1 294 7
1 2947
12 9 4 7
12 9 47
12 94 7
12 947
129 4 7
129 47
1294 7
12947
An invalid number would be 91, 497, 72 and so on.
I tried this but I’m not satisfied with the result:
const combination = (arr) => {
let i, j, temp;
let result = [];
let arrLen = arr.length;
let power = Math.pow;
let combinations = power(2, arrLen);
for (i = 0; i < combinations; i += 1) {
temp = '';
for (j = 0; j < arrLen; j++) {
if ((i & power(2, j))) {
temp += arr[j];
}
}
result.push(temp);
}
return result;
}
const result = combination([1, 2, 9, 4, 7]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Any ideas?
This code does what you want:
const arr = [1, 2, 9, 4, 7],
result = Array.from({length: 2 ** (arr.length - 1)}, (_, index) => index.toString(2).padStart(arr.length - 1, "0"))
.map((binary) => JSON.parse("[" + arr.map((num, position) => num + (Number(binary[position]) ? "," : "")).join("") + "]"));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
It results in:
[
[12947],
[1294, 7],
[129, 47],
[129, 4, 7],
[12, 947],
[12, 94, 7],
[12, 9, 47],
[12, 9, 4, 7],
[1, 2947],
[1, 294, 7],
[1, 29, 47],
[1, 29, 4, 7],
[1, 2, 947],
[1, 2, 94, 7],
[1, 2, 9, 47],
[1, 2, 9, 4, 7]
]
Assuming, the expected result does not depend on order, the spaces represent a binary pattern:
12947 => 0000
1294 7 => 0001
129 47 => 0010
…
1 29 47 => 1010
…
1 2 9 4 7 => 1111
We can utilize this pattern with a counter that we convert to a binary string. We also pad that string with 0 so it always remains 4 digits long:
index.toString(2).padStart(arr.length - 1, "0")
For n digits in arr, there are exactly 2n - 1 combinations, so we use:
{length: 2 ** (arr.length - 1)}
This is an object that has a length property of 2arr.length - 1.
We combine both those things into an Array.from call which accepts two arguments:
an object to turn into an array
a function for mapping each slot
Turning an object with a length property into an array means that we create an array with length many slots.
The mapping function accepts the index of a slot as the second parameter. We only use the index — as a counter for our binary number.
So, finally this whole expression:
Array.from({length: 2 ** (arr.length - 1)}, (_, index) => index.toString(2).padStart(arr.length - 1, "0"))
evaluates to the following array:
[
"0000",
"0001",
"0010",
"0011",
"0100",
"0101",
"0110",
"0111",
"1000",
"1001",
"1010",
"1011",
"1100",
"1101",
"1110",
"1111"
]
We need to further map this to the final result:
.map((binary) => …)
For each array element, binary is one of the binary strings from the array above.
In order to turn e.g. "0110" into something like "12,9,47", we need to map over arr as well. Every digit num from arr should be followed by , at position, iff binary is 1 at position:
arr.map((num, position) => num + (Number(binary[position]) ? "," : "")).join("")
The expression (Number(binary[position]) ? "," : "") evaluates binary at the specified position as a number. If it’s truthy, i.e. anything but 0, it evaluates to ",", if it’s falsy, i.e. 0, it evaluates to "".
So an intermediate array would look like ["1", "2,", "9,", "4", "7"]. All of this is joined together to "12,9,47".
Then, with JSON.parse("[" + … + "]") it’s being treated and parsed as an array, so it turns into [12, 9, 47]. Since these steps are applied for each binary string, you’ll end up with the final result.
2 ** (arr.length - 1) can be replaced by Math.pow(2, arr.length - 1) if ECMAScript 7 is not supported.
{length: 2 ** (arr.length - 1)} can be replaced by new Array(2 ** (arr.length - 1)).
(Number(binary[position]) ? "," : "") can be replaced by ["", ","][Number(binary[position])]. In this case the evaluated number will be used as an index for a temporary array.
So you need to iterate over all the combinations of "space" and "not space" between all the numbers. With n items, there will be n - 1 spaces, and 2 ** (n - 1) different lists.
So you could do something like this to get all the possible lists:
const combination = arr => {
const len = arr.length;
const n = Math.pow(2, len - 1);
const combinations = [];
for (let i = 0; i < n; i++) {
let this_combination = [arr[0]];
for (let j = 1; j < len; j++) {
if (i & Math.pow(2, j - 1)) {
// If the jth bit is on, no space. Append to the last element.
const last_index = this_combination.length - 1;
this_combination[last_index] = +(this_combination[last_index] + '' + arr[j]);
} else {
// Otherwise create a new list item.
this_combination.push(arr[j]);
}
}
// Consider making this function a generator and making this a yield.
combinations.push(this_combination);
}
return combinations;
}
const result = combination([1, 2, 9, 4, 7]);
console.log(result.map(line => line.join(' ')).join('\n'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you wanted each individual item seperately, for each item in the array, combine it with no other item, then just the next item, then the next 2 items, etc. untill the end:
const combination = arr => {
const len = arr.length;
const combinations = [];
for (let i = 0; i < len; i++) {
let item = arr[i];
combinations.push(item);
for (let j = i + 1; j < len; j++) {
item = +(item + '' + arr[j]);
combinations.push(item);
}
}
return combinations;
}
const result = combination([1, 2, 9, 4, 7]);
console.log(result.join('\n'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could take a recursive approach by iterating the array and insert a space or not and fork the calling of the same function with an incremented index.
function combine(array) {
function fork(i, p) {
if (i === array.length) {
result.push(p);
return;
}
fork(i + 1, p + ' ' + array[i]);
fork(i + 1, p + array[i]);
}
var result = [];
fork(1, array[0].toString());
return result;
}
console.log(combine([1, 2, 9, 4, 7]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could do this by using below code where 3 pointer is used,
1st pointer print 0th position to cursor position.
2nd pointer print cursor to diffidence position in each iteration .
3rd pointer print cursor position to last position.
let arr = [1, 2, 9, 4, 7];
console.log(arr.join(','));
for(let diff=2;diff<=arr.length;diff++){
for(i=0,j=diff;arr.length>=i+diff;j++,i++){
var temp = [];
if(i>0)
temp.push(arr.slice(0,i).join(','));
temp.push(arr.slice(i,j).join(''));
if(j<arr.length)
temp.push(arr.slice(j,arr.length).join(','));
console.log(temp.join(','));
}
}
Related
Have the function ArrayChallenge(arr) take the array of integers stored in arr, and determine if any two numbers (excluding the first element) in the array can sum up to the first element in the array. For example: if arr is [7, 3, 5, 2, -4, 8, 11], then there are actually two pairs that sum to the number 7: [5, 2] and [-4, 11]. Your program should return all pairs, with the numbers separated by a comma, in the order the first number appears in the array. Pairs should be separated by a space. So for the example above, your program would return: 5,2 -4,11
If there are no two numbers that sum to the first element in the array, return -1
Input: [17, 4, 5, 6, 10, 11, 4, -3, -5, 3, 15, 2, 7]
Output: 6,11 10,7 15,2
Final Output: --6--,--1----1-- --1--0,7 --1----5--,2
Input: [7, 6, 4, 1, 7, -2, 3, 12]
Output: 6,1 4,3
Final Output: --6--,--1-- 4,3
My approach
function ArrayChallenge(arr) {
var sum = []
for (var i = 0; i < arr.length; i++){
for (var j = i + 1; j < arr.length; j++){
if(arr.[i] + arr[j]=== )
}
}
// code goes here
return arr;
}
// keep this function call here
console.log(ArrayChallenge(readline()));
Can you please help me with this ?
Logic
Loop through the array.
Start from index 1 to last node (except index 0) in the outer loop.
Srart from one node next to the outer loop in the inner loop.
Check the sum of both nodes.
If the sum value is same as the node at first index, push that to sum array in required format.
Check the length of sum array. If length > 0 the join sum array and return. Else return -1
Working Code
const input = [17, 4, 5, 6, 10, 11, 4, -3, -5, 3, 15, 2, 7];
const input2 = [7, 6, 4, 1, 7, -2, 3, 12];
const input3 = [37, 6, 4, 1, 7, -2, 3, 12];
function ArrayChallenge(arr) {
var sum = []
for (var i = 1; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] + arr[j] === arr[0]) {
sum.push([arr[i], arr[j]].join());
}
}
}
return sum.length > 0 ? sum.join(" ") : -1;
}
console.log(ArrayChallenge(input));
console.log(ArrayChallenge(input2));
console.log(ArrayChallenge(input3));
Your approach uses a O(n^2) level complexity. This can be solved using O(n) if you're willing so sacrifice a little on space complexity.
What you can do is :
Make an empty object.
store all values of the array (not the 0th element) in the object as key and add it's value as true.
Loop the array (from 1st index). Take the value and subtract it from the 0th element. find this subtracted value from the object, If it does not return undefined, make a pair and save it.
One drawback of this method is, you'll find duplicate entries in the result.
This Approach uses O(n) Time complexity and O(n) space complexity
function ArrayChallange(arr) {
let numObj = {}
let i = 1
let result = []
let tempVal
// Pushing all elements of arr (from index 1) inside numObj
while(i<arr.length){
numObj[arr[i]] = true
}
i = 1
// Looping the array to find pairs
while(i < arr.length){
tempVal = numObj[Math.abs(arr[0] - arr[i])]
if(tempVal){
result.push(arr[i].toString() +","+tempVal.toString())
}
}
if(result.length !== 0)
return result.join(" ")
else
return -1
}
You could use a reducer followed by a forEach loop in order to push the pairs to an empty array, then join them at the end.
const ArrayChallenge = (nums) => {
const pairs = []
// Get the first and remove it from the array
const first = nums.splice(0, 1)[0]
nums.reduce((all, curr) => {
all.forEach((a) => {
// Check if we have a match
if (curr + a === first) {
// check if it's already in the array
// we don't want duplicates
if (pairs.indexOf(`${a},${curr}`) === -1 && pairs.indexOf(`${curr},${a}`) === -1) {
// push the pair to the array separated by a space
pairs.push(`${curr},${a}`)
}
}
})
return all
}, nums) // we pass in nums as the starting point
// If there are no pairs then return -1
if (pairs.length === 0) {
return -1
} else {
// Join the pairs together with a space
const result = pairs.join(' ')
// Replace each digit (\d) with hyphens before and after
const parsed = result.replace(/(\d)/g, '--$1--')
return parsed
}
}
const result1 = ArrayChallenge([17, 4, 5, 6, 10, 11, 4, -3, -5, 3, 15, 2, 7])
console.log(result1)
const result2 = ArrayChallenge([7, 6, 4, 1, 7, -2, 3, 12])
console.log(result2)
function sumPairs(ints, s) {
let result = [];
for(let i = 0; i < ints.length; i++){
for(let j = 0; j < ints.slice(i); j++){
(ints[i] + ints[j] === s && result.length === 0) ? result.push(ints[i], ints[j]) : 0;
}
} return result;
}
sumPairs([1, 2, 3, 4, 5, 6], 10) //returns [6, 4] instead of [4,6]?
How do I fix this so that the function returns the first pair that add up to s, the second argument? I added the result.length === 0 condition in the if statement a further update would be prevented?
Just iterate over the array using for..of loop and use Set to achieve the desired result.
function sumPairs(ints, s) {
const dict = new Set();
for (let num of ints) {
if (dict.has(s - num)) return [s - num, num];
else dict.add(num);
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
Iterations:
Iteration 1 :=> num = 1 and dict is empty
dict doesn't have 9 (because of s - num i.e 10 - 1) so add num i.e 1 to dict.
Iteration 2 :=> num = 2 and dict has 1
dict doesn't have 8 (because of s - num i.e 10 - 2) so add num i.e 2 to dict
Iteration 3 :=> num = 3 and dict has 1, 2
dict doesn't have 7 (because of s - num i.e 10 - 3) so add num i.e 3 to dict
Iteration 4 :=> num = 4 and dict has 1, 2, 3
dict doesn't have 6 (because of s - num i.e 10 - 4) so add num i.e 4 to dict
Iteration 5 :=> num = 5 and dict has 1, 2, 3, 4
dict doesn't have 5 (because of s - num i.e 10 - 5) so add num i.e 5 to dict
Iteration 6 :=> num = 6 and dict has 1, 2, 3, 4, 5
dict have 4 (because of s - num i.e 10 - 6) so return [s - num, num] i.e [4, 6]
I think you might be overcomplicating things a little. There's no need to slice() or to push(), and there's no need to keep on looping after a result has been found:
function sumPairs(ints, s) {
for (let i = 0; i < ints.length; i++) {
for (let j = i; j < ints.length; j++) {
if (ints[i] + ints[j] == s) {
return [ints[i], ints[j]];
}
}
}
}
console.log(sumPairs([1, 2, 3, 4, 5, 6], 10));
As #robby-cornelissen said there's no need to slice. And there's no need for push too as you can return the result simply.
When you do ints.slice(i) you get an array from that position.
You are comparing an int within an array in the second loop.
It didn't enter the second loop until "i === 5" which is in the ints array a [6]. Notice it didn't enter the second until you get an array of one element. Keep in mind 6 == [6] and 1<[6] and 2<[6] etc
Then it goes incrementing the value of j until you get the position of j that gets the value of ints which, summed by the value of the position i results on s.
const twoSum = (arr, target) => {
arr.sort((a, b) => a - b);
//double pointer -> increment, decrement accordingly
let leftPointer = 0;
let rightPointer = arr.length - 1;
while (leftPointer < rightPointer) {
if (arr[leftPointer] + arr[rightPointer] === target) {
return [arr[leftPointer], arr[rightPointer]];
}
if (arr[leftPointer] + arr[rightPointer] > target) {
rightPointer--;
}
if (arr[leftPointer] + arr[rightPointer] < target) {
leftPointer++;
}
}
};
console.log(twoSum([1, 2, 3, 4, 5, 6], 10));
I'm trying to create a function that groups an array of numbers based on a length parameter. The length represents the max length of each sub-array. The code works as it is meant to for getting the sub arrays, but what I'd like to do is make it sort by odd and even.
function myFunctionA(myArr1, myVal) {
newArr = [];
for ( x = 0; x < myArr1.length; x += myVal) {
newArr.push(myArr1.slice(x, x + myVal));
}
return newArr;
}
Console.log(myfunction([1,2,3,4,5,6,7,8,9,10],3))
This returns [[1,2,3],[4,5,6],[7,8,9],[10]]
What I'd like to do is go through each sub array at a time until the sub arrays are the correct length and add any leftover values to a sub array/s
This would look like
[[1,3,5][2,4,6][7,9][8,10]]
Since arr 0 and arr 1 are the correct length that we have stated in the console.log statement, 7 8 9 and 10 are left over. But since the can't create a full sub array and they are odds and even, they form two sub arrays with a side of 2.
Other examples:
myfunction([1,2,3,4,5,6,7],2)
Should return [[1,3],[2,4],[5,7],[6]]
myfunction([1,2,3,4,5,6,7,8],1)
Should return [[1][2][3][4][5][6][7][8]]
You could take an array for collecting all odd and even values and then push the group if it has zero items. By having the wanted size, create a new array.
function chunkenator(array, size, fn) {
let groups = [],
result = [];
for (let value of array) {
const group = fn(value);
if (!groups[group]) groups[group] = [];
if (!groups[group].length) result.push(groups[group]);
groups[group].push(value);
if (groups[group].length === size) groups[group] = [];
}
return result;
}
console.log(chunkenator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3, x => x % 2));
console.log(chunkenator([1, 3, 5, 7, 8, 9, 11, 13, 15], 3, x => x % 2));
One possibility would be to first seperate the numbers into even and odd numbers and then just loop over it, pushing the numbers into a new array switching between even and odd numbers.
It's not the cleanest piece of code, but it works.
function myfunction(arr, n) {
const evenOdd = arr.reduce((acc, e) => {
const ind = +(e % 2 === 0);
acc[ind] = acc[ind] || [];
acc[ind].push(e);
return acc;
}, []);
let ind = 0, res = [[]];
while (evenOdd[0].length || evenOdd[1].length) {
for (let i = n; i--;) {
const val = evenOdd[ind].shift();
if (val) res[res.length - 1].push(val)
}
ind = (ind + 1) % 2
res.push([])
}
res.pop()
return res;
}
for (const n of [1, 2, 3]) {
console.log(n,
myfunction([1, 2, 3, 4, 5, 6, 7, 8], n)
)
}
I am being stuck in situation where the problem is defined as:
Harshad/Niven numbers are positive numbers that are divisible by the sum of their digits. All single-digit numbers are Harshad numbers.
For example, 27 is a Harshad number as 2 + 7 = 9, and 9 is a divisor
of 27.
Harshad numbers can occur in consecutive clusters. The numbers 1
through 10 are Harshad numbers. The numbers 132 and 133 are both
Harshad numbers. The numbers 1014, 1015, 1016, 1017 are Harshad
numbers.
Create a function that takes a number and returns an array of two
elements. The first element is the length of the Harshad cluster of
which the number is a part. The second is its order in the cluster.
Examples harshad(5) ➞ [10, 5] // cluster = [1, 2, 3, 4, 5, 6, 7, 8, 9,
10] // The second element should be the layman order in the //
cluster, not the programming index.
harshad(133) ➞ [2, 2] // cluster = [132, 133]
so i have figured out a way to find out all the harshed cluster greater than the number passed as arguement to function whose code is defined below
function track(num) {
let a = num.toString().split("");
let b = a.reduce((a, b) => +a + +b, 0);
if (num % b != 0) {return;}
console.log(num,num%b);
if (num % b == 0) {
num++;
track(num);
}
}
track(1015);
so console.log() gives me 1015,1016 and 1017
cluster as they are greater than 1015 which is passed to the function now how can i check for the numbers smaller than 1015 as 1014 should also be the answer but i just cant write another IF statement after the first IF statement and make it as
function track(num) {
let a = num.toString().split("");
let b = a.reduce((a, b) => +a + +b, 0);
if (num % b != 0) {return;}
console.log(num,num%b);
if (num % b == 0) {
num++;
track(num);
}
if(num%b==0){
num--
track(num)
}
}
track(1015);
as this makes no sense
You could separate the functions, one for checking if a number is a harshad value and another which collects these numbers by decrementing the value and incrementing and collecting valid numbers in an array.
function harshad(value) {
function isHarshad(value) {
return value % Array.from(value.toString(), Number).reduce((a, b) => a + b) === 0;
}
var cluster = [],
left = value,
right = value + 1;
while (isHarshad(left)) cluster.unshift(left--);
while (isHarshad(right)) cluster.push(right++);
return [cluster.length, cluster.indexOf(value) + 1];
}
console.log(harshad(5)); // [10, 5] cluster = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log(harshad(133)); // [ 2, 2] cluster = [132, 133]
console.log(harshad(1015)); // [ 4, 2] cluster = [1014, 1015, 1016, 1017]
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this:
function track(num) {
const isHarshed = n => {
let a = n.toString().split("").reduce((a, b) => (+a) + (+b), 0);
return n % a === 0;
};
if (!isHarshed(num)) {return false;}
let index = 1;
let count = 1;
let n = num - 1;
while(isHarshed(n)) {
count++;
index++;
n--;
}
n = num + 1;
while(isHarshed(n)) {
count++;
n++;
}
return [count, index];
}
console.log(track(5));
console.log(track(133));
What i want to achieve is to make every element in array different and unique from others.
So if you imagine such a array:
let myArray = Array(10, 10, 10, 10, 9);
I want to put it through such algorithm:
Takie first element of an array (10) (index = 0).
check if there is element in array with the same value. yes there is - with index 1. if not, check next element...
change myArray[0] to myArray[0] + 1
change myArray[1] to myArray[1] - 1
return myArray
Now array looks like this:
myArray = Array(11, 9, 10, 10, 9)
Now it runs again, and next steps return such array:
myArray = Array(11, 10, 10, 10, 8)
myArray = Array(11, 11, 9, 10, 8)
myArray = Array(12, 10, 9, 10, 8)
myArray = Array(12, 11, 9, 8, 8)
myArray = Array(12, 11, 10, 9, 7)
Now, because there are only unique values, it finishes.
It is easy to make it with while and for loops, but how can i do it with ES6 functional programming?
K.
You could use a nested iteration with short circuit, if two same values are found.
function fn(array) {
return array.some((v, i, a) => a.slice(i + 1).some((w, j) => {
if (v === w) {
++a[i];
--a[i + j + 1];
return true;
}
}));
}
var array = [10, 10, 10, 10, 9];
console.log(array.join(' '));
while (fn(array)) console.log(array.join(' '));
.as-console-wrapper { max-height: 100% !important; top: 0; }
A more functional style, which returns a new array
const
init = j => (v, i, a) => j !== -1
? i === j ? v - 1 : v
: (j = a.indexOf(v, i + 1)) !== -1 ? v + 1 : v,
upDown = () => init(-1);
var array = [10, 10, 10, 10, 9];
do {
console.log(array.join(' '))
} while (array.join() !== (array = array.map(upDown())).join())
.as-console-wrapper { max-height: 100% !important; top: 0; }