I have a bunch of arrays of numbers for example:
let a = [1,2,3];
let b = [4,5,7];
let c = [11,13,17]
I want to create a function that tells me what combination(s) of numbers in the arrays multiplied by numbers in a different array result to a certain number. Below is the code I have so far:
// to get which combination of numbers result to 165
a.forEach(x=>{
b.forEach(y=>{
c.forEach(z=>{
if(x*y*z==165){
console.log(x,y,z)
}
})
})
})
I want to create a function that can be fed an arrays of arrays of numbers such as: [[1,2],[2,5,],[7,11],[13,17]] and give back the combination(s) of numbers that, when multiplied, can result to a certain number.
Here's a recursive function that takes an input number and array of arrays of numbers. It processes through the first array of numbers, finding any that are potential divisors, and if it does, recursively calling itself with the divided input and the balance of the array to see if there are any divisors from that pair of values. If so, they are appended to the current divisor to produce the result:
const findDivisors = (num, arrs) => {
let result = [];
if (arrs.length == 1) {
return arrs[0].filter(n => n == num);
}
arrs[0].forEach(n => {
if (num % n === 0) {
findDivisors(num / n, arrs.slice(1)).forEach(r => result.push([n].concat(r)));
}
});
return result;
}
let a = [1, 2, 3];
let b = [4, 5, 7];
let c = [11, 13, 17];
console.log(findDivisors(165, [a, b, c]));
console.log(findDivisors(136, [a, b, c]));
This expresses the same algorithm from Nick's answer, but written in a very different style:
const findDivisors = (t, [ns, ...nss]) =>
nss .length == 0
? ns .filter (n => n == t) .map (n => [n])
: ns .flatMap (n => t % n == 0 ? findDivisors (t / n, nss) .map (ns => [n, ...ns]) : [])
const ns = [
[1, 2, 3, 5, 6, 9],
[2, 3, 4, 8, 12],
[3, 5, 9, 12, 16, 18]
]
console .log (findDivisors (100, ns))
console .log (findDivisors (144, ns))
console .log (findDivisors (240, ns))
.as-console-wrapper {max-height: 100% !important; top: 0}
I prefer to work with expressions rather than statements. But as far as I see, it offers no advantages or disadvantages over Nick's answer except for questions of style.
It might be better to handle the empty array possibility too, which might look like:
const findDivisors = (t, [ns, ...nss]) =>
ns == undefined
? []
: nss .length == 0
? ns .filter (n => n == t) .map (n => [n])
: ns .flatMap (n => t % n == 0 ? findDivisors (t / n, nss) .map (ns => [n, ...ns]) : [])
Related
In the game idle heroes, demon bells can be level 1,2,3,4. A level 4 is made of 4 level 1, a level 3 is made of 3 level 1 and so on.
I want to find all arrangements of db given a fixed number. I made this recursive algorithm in javascript:
Closer with a more simplified approach:
function findDB(numDB, arr) {
console.log("findDB"+numDB);
if (numDB == 1) {
console.log("HERE2");
return 1;
} else {
for (let i = 1; i < numDB; i++) {
console.log("FOR"+i);
console.log("COND" +(numDB + (numDB-i)));
if((numDB + (numDB-i)) > numDB+1)
continue;
arr= arr.concat([numDB,[i,findDB(numDB - i, arr)]]);
}
return arr;
}
}
var final = []
var y = findDB(3, final);
console.log(JSON.stringify(y));
Output:
findDB(2) CORRECT!
findDB2
FOR1
COND3
findDB1
HERE2
[2,[1,1]]
FindDB(3) is missing 1,1,1,
findDB3
FOR1
COND5
FOR2
COND4
findDB1
HERE2
[3,[2,1]]
here is intended output for input 1 through 6 (algo needs to scale for any number input)
/1/ (1)
/2/ (2),
(1,1)
/3/ (3),
(2,1),
(1,1,1)
/4/ (4),
(3,1),
(2,2),(2,1,1),
(1,1,1,1)
/5/ (4,1),
(3,2),(3,1,1),
(2,2,1),(2,1,1,1),
(1,1,1,1,1)
/6/ (4,2),(4,1,1),
(3,3),(3,2,1),(3,1,1,1),
(2,2,2),(2,2,1,1),(2,1,1,1,1)
(1,1,1,1,1,1)
This is called the partitions of a number, and is a well-known problem. I'm sure computer scientists have more efficient algorithms than this, but a naive recursive version might look like this:
const partitions = (n, m = n) =>
m > n
? partitions (n, n)
: m == 1
? [Array (n) .fill (1)]
: m < 1
? [[]]
: [
... partitions (n - m, m) .map (p => [m, ...p]),
... partitions (n, m - 1)
];
[1, 2, 3, 4, 5, 6] .forEach ((n) => console .log (`${n}: ${JSON .stringify (partitions (n))}`))
And if you're worried about the default parameter (there sometimes are good reasons to worry), then you can just make this a helper function and wrap it in a public function like this:
const _partitions = (n, m) =>
m > n
? _partitions (n, n)
: m == 1
? [Array (n) .fill (1)]
: m < 1
? [[]]
: [
... _partitions (n - m, m) .map (p => [m, ...p]),
... _partitions (n, m - 1)
];
const partitions = (n) => _partitions (n, n);
[1, 2, 3, 4, 5, 6] .forEach ((n) => console .log (`${n}: ${JSON .stringify (partitions (n))}`))
in either case, n is the integer we're summing to, and m is the maximum integer we can use. If m is too large, we simply call again with an appropriate m. If it equals 1, then we can only have an array of n 1's. If m reaches zero, then we have only the empty partition. Finally, we have two recursive cases to combine: When we choose to use that maximum number, we recur with the remainder and that maximum, prepending the maximum to each result. And when we don't use the maximum, we recur with the same target value and a decremented maximum.
I feel as though this has too many cases, but I don't see immediately how to combine them.
The time is exponential, and will be in any case, because the result is exponential in the size of n. If we added memoization, we could really speed this up, but I leave that as an exercise.
Update
I was bothered by those extra cases, and found an Erlang answer that showed a simpler version. Converted to JS, it might look like this:
const countdown = (n) => n > 0 ? [n , ...countdown (n - 1)] : []
const _partitions = (n, m) =>
n < 0
? []
: n == 0
? [[]]
: countdown (m) .flatMap (x => _partitions (n - x, x) .map (p => [x, ...p]))
We have a quick helper, countdown to turn, say 5 into [5, 4, 3, 2, 1]. The main function has two base cases, an empty result if n is negative and a result containing only the empty partition if n is zero. Otherwise, we countdown the possibilities for the maximum value in a single partition, and recur on the partitions for the target less than this new maximum, adding the maximum value to the front of each.
This should have similar performance characteristics as the above, but it somewhat simpler.
Here is a recursive function that produces the results you want. It attempts to break down the input (numDB) into parts up to the maximum number (maxDB, which defaults to 4). It does this by taking the numbers from numDB down to 1 and adding all the possible results from a recursive call to that number, noting that the value of maxDB has to change to be no more than the first number.
const findDB = function(numDB, maxDB = 4) {
if (numDB == 0) return [ [] ];
let result = [];
let thisDB = Math.min(numDB, maxDB);
for (let i = thisDB; i > 0; i--) {
findDB(numDB - i, Math.min(i, thisDB)).forEach(n => {
result.push([i].concat(n));
});
}
return result;
}
;
[6, 5, 4, 3, 2, 1].forEach((i) => console.log(JSON.stringify(findDB(i))))
.as-console-wrapper {
min-height: 100% !important;
}
I've written the above function in the style in your question, with the use of various ES6 Array methods it can be simplified:
const DBlist = (n) => [...Array(n).keys()].map(k => n - k)
const findDB = (numDB, maxDB = 4) => {
if (numDB == 0) return [ [] ];
const thisDB = Math.min(numDB, maxDB);
return DBlist(thisDB).flatMap((i) => findDB(numDB - i, Math.min(i, thisDB)).map(a => [i, ...a]))
}
DBlist(6).forEach((n) => console.log(JSON.stringify(findDB(n))))
.as-console-wrapper {
min-height: 100% !important;
}
As you can see in my code, the odd numbers are ascended, but the even numbers are eliminated. I want the even numbers to stay in their places. The expected log would be [1, 3, 2, 8, 5, 4]
function sortArray(array) {
let sortedNumbers = array.sort();
let newArray = [];
for (let i = 0; i < sortedNumbers.length; i++) {
if (sortedNumbers[i] % 2 !== 0) {
newArray.push(sortedNumbers[i]);
}
}
return newArray;
}
console.log(sortArray([5, 3, 2, 8, 1, 4]));
I think the clearest way to do this would be to extract all the odd numbers into a separate array, sort that array, then insert them back into the original array:
function sortArray(array) {
const odds = array.filter(num => num % 2 === 1);
odds.sort((a, b) => a - b);
return array.map(
num => num % 2 === 1 ? odds.shift() : num
);
}
console.log(sortArray([5, 3, 2, 8, 1, 4]))
Note that you can't use .sort, because .sort compares lexicographically (eg 11 will come before 2, which is wrong) - use .sort((a, b) => a - b); instead.
I'm not sure what "ascended" means, but for instance if you wanted to add 0.1 to each odd number while leaving the evens as they are, you could simply add an else statement as follows.
Note that providing the numericSort function is necessary unless you want your numbers to be sorted alphabetically (which is the default for the .sort method.)
const numericSort = (a, b) => a - b;
function sortArray(arr) {
const
sortedNumbers = arr.sort(numericSort),
newArray = [];
for(num of sortedNumbers) {
if (num % 2 !== 0) { newArray.push(num + 0.1); }
else { newArray.push(num); }
}
return newArray;
}
console.log(sortArray([5, 31, 20, 8, 1, 4]))
What is the best way to implement a function that takes three arguments
smallest length of combinations
highest length of combinations
array of values
and returns all combinations of length l (arg1 <= l <= arg2). E.g.
getComb (2, 2, [1, 2, 3]) === [[1,2], [2,3], [3,1]]
getComb (0, 3, [1, 2, 3]) === [[],[1],[2],[3],[1,2],[2,3],[3,1],[1,2,3]]
(=== is defined here as deep equals without respect to order (almost set equality for both depths of the array) Also duplicate values should be ignored (e.g. getComb(a, b, [x,x,y]) === getComb(a, b, [x,y]) for all a,
b, x, y)
Then a fn to get all combinations can be implemented:
getAllComb = arr => getComb (0, arr.length, arr)
Thanks!
Here's another recursive solution, structured slightly differently from the answer by Nina Scholz. It has a function to choose exactly n elements from the list, and then uses that in the main function, which calls it for each value from min to max:
const choose = (n, xs) =>
n < 1 || n > xs .length
? []
: n == 1
? [...xs .map (x => [x])]
: [
...choose (n - 1, xs .slice (1)) .map (ys => [xs [0], ...ys]),
...choose (n , xs .slice (1))
]
const getCombs = (min, max, xs) =>
xs .length == 0 || min > max
? []
: [...choose (min, xs), ...getCombs (min + 1, max, xs)]
console .log (
getCombs (0, 3, [1, 2, 3]),
getCombs (2, 2, [1, 2, 3])
)
Here getCombs is the main function, and should be fairly clear, just concatenating the result of choose (min, xs) with the result of the recursive call to getCombs (min + 1, max, xs). choose is a nicely reusable function which operates on a double recursion, the first one selecting all those combinations which use the initial element and the second all those that don't.
This doesn't quite match Nina's solution, as it ignores the empty list when min is zero. If you want one that includes the empty list, you could change choose to the (slightly uglier, IMHO) version:
const choose = (n, xs) =>
n < 1 || n > xs .length
? [[]]
: [
...choose (n - 1, xs .slice (1)) .map (ys => [xs [0], ...ys]),
...(n + 1 > xs .length ? [] : choose (n , xs .slice (1)))
]
one way to implement getComb is :
[1,2,3].reduce( (acc, v, i, original) =>
acc.concat(original.slice(i+1).map( w => [w, v] )),
[]);
You could take a recursive approach.
function getComb(min, max, array) {
function iter(left, right = [], push = true) {
if (push && min <= right.length && right.length <= max) result.push(right);
if (!left.length) return;
iter(left.slice(1), [...right, left[0]]);
iter(left.slice(1), right, false);
}
var result = [];
iter(array);
return result;
}
console.log(getComb(2, 2, [1, 2, 3]));
console.log(getComb(0, 3, [1, 2, 3]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ok I have a partial solution (for a = 1, b = arr.length):
const list = R.unapply (R.identity)
const xproduct = arr => R.apply (R.liftN (arr.length) (list)) (arr)
const getPerm = arr => xproduct (R.repeat (arr) (arr.length))
const getComb = arr => R.uniq (R.map (R.uniq) (getPerm (arr)))
getComb([1,2,3]) === [[1],[2],[3],[1,2],[2,3],[3,1],[1,2,3]]
There's got to be something better ;)
Here's a solution (atleast to getAllComb) that I'm kinda proud of :) There's a lot of stuff, but most of it is boilerplate
Inspired by bitstrings
// Generic helper functions
const appendIfNotFalse = fn => (acc, val) => R.ifElse (R.equals (false)) (R.always (acc)) (R.flip (R.append) (acc)) (fn (acc, val))
const mapAndFilter = fn => arr => R.reduce (appendIfNotFalse (fn)) ([]) (arr)
// My helper fn
const has1InBitstring = n => idx => (n & 2 ** idx) > 0
// Soltuion
const indices = arr => key => mapAndFilter ((_, j) => has1InBitstring (key) (j) ? j : false) (R.range (0) (arr.length))
const getAllComb = arr => R.times (i => R.props (indices (arr) (i)) (arr)) (2 ** arr.length)
// Example
getAllComb ([1,2,3]) === [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
This question already has answers here:
Finding difference between consecutive numbers in an array in javascript
(4 answers)
Closed 1 year ago.
I have a list of numbers, say numbers = [3,7,9,10] and I want to have a list
containing the differences between neighbor elements - which has to have one
less element - in the given case diffs = [4,2,1]
Of course I could create a new list go through the input list and compile my
result manually.
I'm looking for an elegant/functional (not to say pythonic) way to do this.
In Python you would write [j-i for i, j in zip(t[:-1], t[1:])] or use numpy
for this.
Is there a reduce()/list comprehension approach in JavaScript, too?
You could slice and map the difference.
var numbers = [3, 7, 9, 10],
result = numbers.slice(1).map((v, i) => v - numbers[i]);
console.log(result);
A reversed approach, with a later slicing.
var numbers = [3, 7, 9, 10],
result = numbers.map((b, i, { [i - 1]: a }) => b - a).slice(1);
console.log(result);
You could do this using reduce method
const numbers = [3, 7, 9, 10]
const res = numbers.reduce((r, e, i, a) => i ? r.concat(e - a[i - 1]) : r, []);
console.log(res)
You could also pop after map:
var numbers = [3, 7, 9, 10],
result = numbers.map((v, i) => numbers[i+1]-v);
result.pop()
console.log(result);
you can use map and slice
const numbers = [3, 7, 9, 10, 11, 13];
const res = numbers.map((num, index) => numbers[index + 1] - num).slice(0, -1);
console.log(res)
You can use destructuring assignment and recursion -
const diff = ([ a, b, ...more ]) =>
b === undefined
? []
: [ b - a, ...diff ([ b, ...more ]) ]
console .log (diff ([ 3, 7, 9, 10 ]))
// [ 4, 2, 1 ]
console .log (diff ([ 3 ]))
// []
console .log (diff ([]))
// []
Or skip some intermediate values by using an index -
const diff = (a = [], i = 1) =>
i >= a.length
? []
: [ a[i] - a[i - 1], ...diff (a, i + 1) ]
console .log (diff ([ 3, 7, 9, 10 ]))
// [ 4, 2, 1 ]
console .log (diff ([ 3 ]))
// []
console .log (diff ([]))
// []
If needed, make it stack-safe using loop and recur. This one runs really fast, too -
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let r = f ()
while (r && r.recur === recur)
r = f (...r.values)
return r
}
const push = (a = [], v) =>
( a .push (v)
, a
)
const diff = (a = []) =>
loop
( ( i = 1
, r = []
) =>
i >= a.length
? r
: recur
( i + 1
, push (r, a[i] - a[i - 1])
)
)
console .log (diff ([ 3, 7, 9, 10 ]))
// [ 4, 2, 1 ]
console .log (diff ([ 3 ]))
// []
console .log (diff ([]))
// []
You can slice (0 as a start, -1 to skip the last item) and map so to generate the differences between an element and its successor in the sequence:
const items = [3,7,9,10];
console.log(items.slice(0,-1).map((e,i)=>items[i+1]-e))
I want to sort only odd numbers without moving even numbers. For example, when I write :
sortArray([5, 3, 2, 8, 1, 4])
The expected result is :
[1, 3, 2, 8, 5, 4]
I am new to JavaScript and I came across a challenge on the Internet that has me perplexed. I normally wouldn't post asking for a solution on the Internet, BUT I have tried for hours and I would like to learn this concept in JavaScript.
The challenge states :
You have an array of numbers.
Your task is to sort ascending odd numbers but even numbers must be on their places.
Zero isn't an odd number and you don't need to move it. If you have an empty array, you need to return it.
Here is my code so far, please take it easy on me I am in the beginning stages of programming.
function sortArray(array) {
let oddNums = [];
for(let i = 0; i < array.length; i++) {
if(array[i] % 2 !== 0) {
oddNums.push(array[i]);
}
}
oddNums = oddNums.sort((a,b)=> a-b);
array.concat(oddNums);
array = array.sort((a,b) => a-b);
return array;
}
You could take a helper array for the odd indices and another for the odd numbers, sort them and apply them back on the previously stored indices of the original array.
var array = [5, 3, 2, 8, 1, 4],
indices = [];
array
.filter((v, i) => v % 2 && indices.push(i))
.sort((a, b) => a - b)
.forEach((v, i) => array[indices[i]] = v);
console.log(array);
Here's a solution using mostly the built-in array methods. Get a list of just the odds, sort it, then map through the original, replacing each item with the first sorted odd if the item is odd, or itself if even:
const array = [5, 3, 2, 8, 1, 4] // to: [1, 3, 2, 8, 5, 4]
function sortOddsOnly(arr) {
const odds = arr
.filter(x => x%2)
.sort((a, b) => a - b);
return arr
.map(x => x%2 ? odds.shift() : x);
}
console.log(sortOddsOnly(array));
I have a solution like this.
Build a sorted odd number array 1st, and then fill the rest of even numbers in order:
const arr = [5, 3, 2, 8, 1, 4];
const odd = arr.filter(i => i%2 !== 0).sort();
let i = 0,
result = [];
arr.forEach(e => {
if (e%2 === 0) {
result.push(e)
} else {
result.push(odd[i]);
i++;
}
});
console.log(result);
just do:
arr.sort((a, b) => a%2 && b%2 ? a - b : 0)
If that works depends on the sort algorithm your browser uses.
A browserindependent version:
for(const [i1, v1] of arr.entries())
for(const [i2, v2] of arr.entries())
if( v1%2 && v2%2 && (i1 < i2) === (v1 > v2))
([arr[i1], arr[i2]] = [v2, v1]);
One of the possible solutions is this. What I have done is created new array odd(array with odd position in original array using Array.prototype.filter) and then sort that array using Array.prototype.sort. Then using Array.prototype.map change value of all odd element of original array with odd array.
x1=[5, 3, 2, 8, 1, 4];
function sortArray(array) {
var odd = array.filter((x,i) => (i+1) % 2 ).sort((a,b) => a > b); //sort odd position and store that in new array
return array.map((x,i) => (i+1) % 2 ? odd.shift() : x ); //if i is odd then replace it with element from
//odd array otherwise keep the element as it is
}
console.log(sortArray(x1));
Here is a possible solution using a slightly customized selection sort :
var xs = [5, 3, 2, 8, 1, 4];
console.log(sortOddsOnly(xs));
function sortOddsOnly (xs) {
var n = xs.length;
for (var i = 0; i < n - 1; i++) {
if (xs[i] % 2 === 1) {
for (var j = i + 1; j < n; j++) {
if (xs[j] % 2 === 1) {
if (xs[i] > xs[j]) {
var min = xs[j];
xs[j] = xs[i];
xs[i] = min;
}
}
}
}
}
return xs;
}
The first two if guarantee that we swap only odd numbers (x % 2 === 1 means "x is odd").
def sort_array(source_array):
b = sorted([n for n in source_array if n % 2 != 0])
c = -1
d = []
for i in source_array:
c = c+1
if i % 2 != 0 :
d.append(c)
for x in range (len(d)):
z = d[x]
source_array[z] = b[x]
return source_array