How to un-nest this recursive algorithm in javascript? - javascript

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;
}

Related

Sum all numbers in array until a certain value is reached

I'm writing a function and this is the last piece of the puzzle, which I thought would be easy to deal with, but after some unsuccessful tinkering with for and while loops, I tried looking it up online and still couldn't find an answer. I came across some obscure and complex solutions, but I think there should be a more straightforward way to solve this. For example, if I have an array
[1, 2, 3, 5, 7, 9]
And the argument is 10, the function should return 6 (1 + 2 + 3), because the sum of the values should be <= 10 (or whatever number is passed). If the argument is 4, the function should return 3 (1 + 2) and so on.
You can use a for loop:
const arg = 10
const arr = [1, 2, 3, 5, 7, 9]
let res = 0;
const calc = (arr, limit) => {
for (num of arr) {
if (num + res > limit) {
break;
}
res += num;
}
return res;
}
console.log(calc(arr, arg))
.reduce() each current value (cur) added to the accumulator (acc) and checked vs. the limit (max). If acc + cur is less than limit then return acc+ cur, otherwise return acc. Added .sort() if the array happens to be out of order, as per Spectric's comment.
const array = [1,2,3,5,6,8];
const mixed = [0,7,3,8,2,1];
const A = 10;
const B = 15;
const closest = (arr, max) => {
return arr.sort((a, b) => a - b).reduce((acc, cur) =>
(acc + cur) > max ? acc : (acc + cur));
}
console.log(closest(array, A));
console.log(closest(array, B));
console.log(closest(mixed, B));
One interesting approach is to realize that we want to do a fold (something like Array.prototype.reduce) but one which we can escape early. The answer from zer00ne does this by choosing to check the condition on every iteration, and just continually returning the accumulator each time the condition is not met. That's fine for many use-cases, but it would be nice to make it more explicit.
I know of two ways to do this. One is to have some signal value that we would return -- probably a symbol -- to say, "We're done, just return the accumulator." The downside is that this function now depends on that external signal value. It's not terrible, and often might be the right solution. It's not hard to write, and I'll leave it as an exercise.
The other technique is to require the callback to explicitly choose whether to continue the iteration or stop by supplying it with next and done functions. If we want to continue, we call next with the next accumulator value. If we're finished, we just call done. Here's a version of that:
const fold = (fn) => (a) => ([x, ...xs]) =>
x == undefined ? a : fn (a, x, (r) => fold (fn) (r) (xs), () => a)
const sumUpTo = (n) =>
fold ((a, x, next, done) => a + x > n ? done () : next (a + x)) (0)
console .log (sumUpTo (10) ([1, 2, 3, 5, 7, 9])) //=> 6
console .log (sumUpTo (4) ([1, 2, 3, 5, 7, 9])) //=> 3
console .log (sumUpTo (10) ([1, 2, 3, 4, 5, 6])) //=> 10
sumUpTo takes our total value and returns a function that takes a list of numbers. It does this by calling fold using a callback function, the initial value (0 for a sum), and eventually passing our list of numbers. That callback does the work we care about. Then fold repeatedly calls it until it runs out of values or done is called.
We can break down the one-liner version above to focus specifically on the callback, if it makes it more clear:
const callback = (n) => (a, x, next, done) =>
a + x > n
? done ()
: next (a + x)
const sumUpTo = (n) => fold (callback (n)) (0)
It's a very elegant pattern, to my mind.
Quickest way with smallest code footprint:
const dataset = [1, 2, 3, 5, 7, 9]
const getMaxSum = (dataset, max) => {
var sum = 0, num;
for( num of dataset ) {
if( sum + num > max ) break // very important to break once satisfied
sum += num
}
return sum
}
console.log( getMaxSum(dataset, 10) )
console.log( getMaxSum(dataset, 20) )

Recursive forEach() in javascript

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]) : [])

Best way to get combination of array of elements in Ramda?

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]]

Calling and Passing Nested Functions in JavaScript

I have a function that returns the LCM of a range of numbers. It works great, but this has a function inside of a function inside of a function. My question is why can I not simplify the nested smallestCommon() by removing scm() from inside of it? Why does this particular solution need this if else functionality so deeply nested?
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
var candidate = max;
var smallestCommon = function(low, high) {
// inner function to use 'high' variable
function scm(l, h) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high);
}
}
return scm(low, high);
};
for (var i = min; i <= max; i += 1) {
candidate = smallestCommon(i, candidate);
}
return candidate;
}
smallestCommons([5, 1]); // should return 60
smallestCommons([1, 13]); // should return 360360
smallestCommons([23, 18]); //should return 6056820
Having inner functions isn't necessarily bad. Sometimes you want to reduce some local duplication, but don't want to also create a new top-level function. Used carefully, they can clean up code.
In your particular case though, it isn't necessary to have it nested. You can just pass in the high variable as a third parameter:
function scm(l, h, high) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + high, high);
}
}
function smallestCommon (low, high) {
return scm(low, high, high);
}
This is actually a fairly common pattern when dealing with recursion: have a recursive function, and a helper function that simplifies calling the recursive function. In functional languages where recursion is common though, it's actually commonplace to have a local recursive function like you had originally (often called something like go).
And it's a shame that JS doesn't have a range function. smallestCommons is basically just a reduction over the range [min,max]. Between the lack of range function and smallestCommon having it's arguments in the wrong order though, converting your code to use reduce unfortunately got a little bulky:
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return Array.from(new Array(max - min), (x,i) => i + min)
.reduce((acc, i) => smallestCommon(i, acc), max);
}
I'll suggest breaking this down into smaller parts. Instead of one function that's complicated and difficult to debug, you'll have lots of functions that are easy to write and debug. Smaller functions are easier to test and reuse in other parts of your program too -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
console.log
( lcm (1, 5) // 5
, lcm (3, 4) // 12
, lcm (23, 18) // 414
)
Now we have minmax. Unique to this implementation is that it finds the min and the max using only a single traversal of the input array -
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...rest ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( rest
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
console.log
( minmax ([ 3, 4, 2, 5, 1 ]) // [ 1, 5 ]
, minmax ([ 1, 5 ]) // [ 1, 5 ]
, minmax ([ 5, 1 ]) // [ 1, 5 ]
, minmax ([ 9 ]) // [ 9, 9 ]
, minmax ([]) // [ Infinity, -Infinity ]
)
By default minmax returns a list of the min and max values. We can plug the min and max directly into a range function, which might be more useful to us, as we'll see later -
const range = (m, n) =>
m > n
? []
: [ m, ... range (m + 1, n ) ]
console.log
( minmax ([ 3, 4, 2, 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 1, 5 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 5, 1 ], range) // [ 1, 2, 3, 4, 5 ]
, minmax ([ 9 ], range) // [ 9 ]
, minmax ([], range) // []
)
Now that we can find the min and max of the input, create a range between the two, all that's left is calculating the lcm of the values in the range. Taking many values and reducing them to a single value is done with .reduce -
console.log
( minmax ([1, 5], range) .reduce (lcm, 1) // 60
, minmax ([5, 1], range) .reduce (lcm, 1) // 60
)
Wrap that up in a function and we're done -
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
Verify the result in your own browser below -
const gcd = (m, n) =>
n === 0
? m
: gcd (n, m % n)
const lcm = (m, n) =>
Math.abs (m * n) / gcd (m, n)
const None =
Symbol ()
const list = (...values) =>
values
const minmax = ([ x = None, ...xs ], then = list) =>
x === None
? then (Infinity, -Infinity)
: minmax
( xs
, (min, max) =>
then
( Math.min (min, x)
, Math.max (max, x)
)
)
const range = (m, n) =>
m > n
? []
: [ m, ... range (m + 1, n ) ]
const smallestCommons = xs =>
minmax (xs, range) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
extra
Above, minmax is defined using continuation passing style. We save extra computation by passing range as the specified continuation (then). However, we can call minmax without specifying a continuation and spread (...) the intermediate value to range. Either program might make more sense to you. The result is the same -
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1)
console.log
( smallestCommons ([ 5, 1 ]) // 60
, smallestCommons ([ 1, 13 ]) // 360360
, smallestCommons ([ 23, 18 ]) // 6056820
)
same pig, different farm
smallestCommons is basically just a reduction over the range [min,max] - #Carcigenicate
Hopefully it helps to see the same result from multiple approaches :D
sourface
Some people will despise the above implementation of minmax regardless of its elegance and flexibility. Now that we maybe understand reducing a little better, we can show how minmax might be better implemented using direct style -
const minmax = xs =>
xs .reduce
( ([ min, max ], x) =>
[ Math.min (min, x)
, Math.max (max, x)
]
, [ Infinity, -Infinity ]
)
const smallestCommons = xs =>
range (...minmax (xs)) .reduce (lcm, 1) // direct style now required here
You can unnest it, if you rewrite the inner functions in such a way, that they don't reference variables in their outer scope.
function scm(l, h, step) {
if (h % l === 0) {
return h;
} else {
return scm(l, h + h, step);
}
}
function smallestCommons(arr) {
var max = Math.max(...arr);
var min = Math.min(...arr);
return scm(min, max, max);
}
It might blow your stack though, but that's a different problem. If you get a RangeError, you have to rewrite scm to be loop based instead of recursive.

How to sort an array of odd numbers in ascending order, but keep even numbers at their position?

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

Categories

Resources