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]]
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;
}
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]) : [])
EDIT: So I changed my code to the following:
function countTinyPairs(a, b, k) {
let pairs = 0;
let arr = [];
b.reverse()
for (num in a) {
result = String(a[num]) + String(b[num])
if (result < k) {
pairs++
}
}
return pairs
}
It works the exact same, without needing to check new arr/push, etc. Would this run in less time? Is there a way to check myself how long it takes?
I was doing a Codesignal javascript practice test (now finished). I had a really hard time, and now know that I need a lot more practice before I can even think of doing the actual test. One of the questions was:
"You are given two arrays of integers a and b of the same length, and an integer k. We will be iterating through array a from left to right, and simultaneously through array b from right to left, and looking at pairs (x, y), where x is from a and y is from b. Such a pair is called tiny if the concatenation xy is strictly less than k."
This was the code that I wrote:
function countTinyPairs(a, b, k) {
let pairs = 0;
let arr = [];
b.reverse()
for (num in a) {
for (num in b) {
result = String(a[num]) + String(b[num])
if (result < k) {
if ((arr.findIndex(e => e === result)) === -1) {
arr.push(String(result));
pairs++
}
}
}
}
return pairs
}
It works, except execution time limit is 4 seconds. There is a hidden test case where my function takes longer than 4 seconds to complete (I'm assuming the arrays have an extreme amount of numbers). I haven't learned anything about the Big O (or whatever it's called) yet, so I have no clue on anything about it.
I'm guessing I'd have to learn about it before I could successfully solve this problem on my own? Or, did I just write bad code and it's possible to do it with better code without knowing a thing about Big O?
First of all, there is no need for multiple loops. You have three:
b.reverse() will reverse b in-place with likely O(n) complexity. Even if it's O(log n) it's still unnecessary.
for (num in a) iterates over a in O(n).
for (num in b) iterates over b in O(n). However, since it's an inner loop, the total is O(n^2).
arr.findIndex(e => e === result) will trigger another O(m) iteration over any pair found. Depending on the value of k that might be only a few times or many. It's already in an O(n^2), so worst case scenario is a high value of k that covers every combination of pairs, so it will be triggered every time and thus you would get a O(n^3) complexity.
Eliminate multiple loops over a and b
Given that both a and b are of equal length, we can trivially iterate over both arrays with a single loop. To achieve reverse iteration, we can employ basic arithmetic to get the index for b that has the same distance from the end as the index of a has from the beginning. Or in other words, you can do this to iterate over both arrays at once in two directions:
const a = [2, 9, 2];
const b = [5, 3, 5];
for (let i = 0; i < a.length; i++) {
const j = b.length - i - 1; //reverse the index for `b`
console.log(`${a[i]}, ${b[j]}`);
}
Note that a.length and b.length are interchangeable, as the problem description says they are identical.
Drop the constant lookups in arr
The next problem is that arr is repeatedly being iterated over only to check the existence of a pair. Instead you can use a Set. Lookups and inserts will have sub-linear complexity by specs. Many implementations can even give you O(1). You can simplify your code to
const pairs = new Set();
/* ... if a pair is found ... */
pairs.add(result);
/* ... produce count ... */
return pairs.size;
Summary
The complete solution can look like this and you only need to iterate once through both a and b at the same time:
function countTinyPairs(a, b, k) {
let pairs = new Set();
for (let i = 0; i < a.length; i++) {
const j = b.length - i - 1;
const pair = `${a[i]}${b[j]}`;
if (Number(pair) < k) {
pairs.add(pair);
}
}
return pairs.size;
}
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
Alternative
This can also be expressed using array methods leading to shorter code at the cost of two loops with .map and .filter, then a third to convert to a Set:
function countTinyPairs(a, b, k) {
let pairs = a
.map((x, index) => `${x}${b[b.length - index - 1]}`) //produce pair
.filter(x => Number(x) < k); //leave only tiny ones
return new Set(pairs).size; //deduplicate and count
}
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
Using .reduce to bring it down to one loop again:
function countTinyPairs(a, b, k) {
let pairs = a
.reduce((acc, x, index) => {
const pair = `${x}${b[b.length - index - 1]}`;
if (Number(pair) < k) {
return acc.add(pair);
}
return acc;
}, new Set());
return pairs.size; //deduplicate and count
}
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
Finally, if you hate yourself you can very make it into a single expression:
const countTinyPairs = (a, b, k) =>
a.reduce(
(acc, x, index) =>
(pair => (Number(pair) < k) ? acc.add(pair) : acc)
(`${x}${b[b.length - index - 1]}`),
new Set()).size;
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
No discarding of duplicates
If there is no need to remove duplicates, then the whole code becomes even simpler - you only need to maintain a count, not even collect the pairs:
function countTinyPairs(a, b, k) {
let pairs = 0;
for (let i = 0; i < a.length; i++) {
const j = b.length - i - 1;
const pair = `${a[i]}${b[j]}`;
if (Number(pair) < k) {
pairs++;
}
}
return pairs;
}
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
Or using array methods:
.map() + .filter()
function countTinyPairs(a, b, k) {
let pairs = a
.map((x, index) => `${x}${b[b.length - index - 1]}`) //produce pair
.filter(x => Number(x) < k); //leave only tiny ones
return pairs.length;
}
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
.reduce()
function countTinyPairs(a, b, k) {
let pairs = a
.reduce((count, x, index) => {
const pair = `${x}${b[b.length - index - 1]}`;
if (Number(pair) < k) {
return count + 1;
}
return count;
}, 0);
return pairs;
}
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
Single expression .reduce()
const countTinyPairs = (a, b, k) =>
a.reduce(
(count, x, index) =>
count + (Number(`${x}${b[b.length - index - 1]}`) < k),
0);
const a = [2, 9, 2];
const b = [5, 3, 5];
console.log(countTinyPairs(a, b, 30));
The wording of the question is somewhat ambiguous and it doesn't help that a concrete input and expected output have not been provided. Here's how I would write the solution based on my understanding of the question -
const countTinyPairs = (a, b, k) =>
loop
( ( [ x, xs ] = likeList(a)
, [ y, ys ] = likeList([...b].reverse())
, pairs = 0
) =>
x == null || y == null
? pairs
: recur
( xs
, ys
, Number(`${x}${y}`) < k
? pairs + 1
: pairs
)
)
console.log(countTinyPairs([1,2,3,4,5], [3,4,5,6,7], 40))
// => 3
Using our own generic functions, loop, recur, and likeList, we can dramatically reduce the conceptual overhead required to derive the answer -
const likeList = (t = [], c = 0) =>
({ [Symbol.iterator]: _ => [ t[c], likeList(t, c + 1) ].values() })
const recur = (...v) =>
({ recur, [Symbol.iterator]: _ => v.values() })
const loop = (f, ...init) =>
{ let r = f(...init)
while (r && r.recur === recur)
r = f(...r)
return r
}
If you'd like to learn more about the design choices for these helpers, I encourage you to see this related Q&A.
Expand the snippet below to run the program and verify the results in your own browser -
const likeList = (t = [], c = 0) =>
({ [Symbol.iterator]: _ => [ t[c], likeList(t, c + 1) ].values() })
const recur = (...v) =>
({ recur, [Symbol.iterator]: _ => v.values() })
const loop = (f, ...init) =>
{ let r = f(...init)
while (r && r.recur === recur)
r = f(...r)
return r
}
const countTinyPairs = (a, b, k) =>
loop
( ( [ x, xs ] = likeList(a)
, [ y, ys ] = likeList([...b].reverse())
, pairs = 0
) =>
x == null || y == null
? pairs
: recur
( xs
, ys
, Number(`${x}${y}`) < k
? pairs + 1
: pairs
)
)
console.log(countTinyPairs([1,2,3,4,5], [3,4,5,6,7], 40))
// 3
There's room for an optimisation here. Here we introduce likeReversedList -
const likeReversedList = (t = [], c = 0) =>
({ [Symbol.iterator]: _ => [ t[t.length - c - 1], likeReversedList(t, c + 1) ].values() })
const countTinyPairs = (a, b, k) =>
loop
( ( [ x, xs ] = likeList(a)
, [ y, ys ] = likeList([...b].reverse())
, [ y, ys ] = likeReversedList(b) // <-
, pairs = 0
) =>
// ...
)
The complexity of your code is O(n^2)
Here is how I would solve it. I hope I got the task right, please post some examples of input/output.
If a and b are of equal length you can iterate through them with a single loop. The complexity would be O(n) where n is the length of a.
Why check for duplicates? Is that a requirement?
function test(a,b,k)
{
let x,y,i,xy, result =[];
for (i=0;i<a.length;i++)
{
x = a[i];
y = b[b.length - 1 -i]
xy = parseInt([x,y].join(''));
if (xy < k) result.push(xy);
}
return result;
}
let a = [1,2,3,4,5], b=[4,5,6,7,8], k = 40;
console.log(test(a,b,k));
// Output: [18, 27, 36]
You are given two arrays of integers a and b of the same length. The length is the same so we need to iterate only once improving it from O(n^2) to O(n). You still need to check every element, so that is the best possible complexity for this problem.
The if statement checking for duplicates is as unneeded as the variable pairs.
You can use a Set that will check for duplicates and in the end, return its length instead of counting the pairs manually.
I'm attaching the examplary solution below:
const countTinyPairs = (a, b, k) => {
const set = new Set();
for (let i = 0, j = b.length-1; i < a.length; i++, j--) {
const result = String(a[i]) + String(b[j])
if (result < k) {
set.add(result);
}
}
return set.size;
}
console.log(countTinyPairs([1,2,3,4,5], [1,2,3,4,5], 40))
Edit it is not necessary to have a separate variable called j, but I thought it wad more readable having in stored in a variable.
If we don't need to check for duplicates, then it's enough to write it like this:
const countTinyPairs = (a, b, k) => {
let pairs;
for (let i = 0, j = b.length-1; i < a.length; i++, j--) {
if (String(a[i]) + String(b[j])< k) pairs++
}
return pairs;
}
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
What i'm trying to do is make a recursive version of find, which takes an array and a test function and returns first element of an array, that passes the test. Lets look at the example:
function isEven(num) { return(num%2 == 0); }
var arr = [1, 3, 5, 4, 2];
function findRecursive(arr, func) {
var p = arr.shift();
if (func(p) == true)
return p;
else
findRecursive(arr, func);
}
findRecursive(arr, isEven);
By some reason i'm getting undefined. But if i change shift to pop on line 5, it correctly returns 2. What causes th problem?
You need to return the value of the recursive call, otherwise you return undefined, the standard return value of a function in Javascript.
} else {
return findRecursive(arr, func);
// ^^^
}
You may insert a check for the length of the array, if there is no more element to check. Then you could return undefined intentionally.
function isEven(num) { return num % 2 === 0; }
function findRight(array, fn) {
if (!array.length) {
return;
}
var p = array.pop();
return fn(p) ? p : findRight(array, fn);
}
console.log(findRight([1, 3, 5, 4, 2], isEven)); // 2
console.log(findRight([1, 3, 5], isEven)); // undefined
Recursion is a looping mechanism that was born in the context of functional programming; taking it out of that context only permits a crude understanding of how recursion is meant to be used
Recursion, when used with other functional programming practices like persistent (immutable) data types and pure functions, can be expressed beautifully as a pure expression
const find = (f, [x,...xs]) =>
x === undefined
? x
: f (x)
? x
: find (f, xs)
const isEven = x =>
(x & 1) === 0
console.log (find (isEven, [1, 3, 5, 4, 2])) // 4
console.log (find (isEven, [1, 3, 5, 7, 9])) // undefined
Be careful with recursion in JavaScript, tho – use a stack-safe looping mechanism to avoid blowing the stack on a large array
const recur = (...values) =>
({ type: recur, values })
const loop = f =>
{
let acc = f ()
while (acc && acc.type === recur)
acc = f (...acc.values)
return acc
}
const find = (f, xs) =>
loop ((i = 0) =>
i === xs.length
? undefined
: f (xs [i])
? xs [i]
: recur (i + 1))
const isEven = x =>
(x & 1) === 0
// [ 1, 2, 3, 4, ... 20000 ]
const numbers =
Array.from (Array (2e4), (x,n) => n + 1)
console.log (find (isEven, numbers)) // 2
// this would have blown the stack using the first version of `find`
// but it works just fine here, thanks to loop/recur
console.log (find (x => x < 0, numbers)) // undefined