How to generate an array of incremental values from a given array
the idea is to create a kind of diamond shape where the arrays start decreasing in size once they reach the middle of the array. In other words the longest array is going to be the one that is containing the middle value of the array or (array.length/2 + 1)
and in cases where the elements are short to complete the array on the second half just replace it with 'E' to indicate empty space just like on the second example.
example 1
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p']
//the longest array in length is containing 'i' which is the value at
array.length/2 + 1
var output = [
['a'],
['b','c'],
['d','e','f'],
['g','h','i','j'],
['k','l','m'],
['n','o'],
['p']
]
example 2
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t']
enter code here
//the longest array in length is containing 'k' which is the value at array.length/2 + 1
var output = [
['a'],
['b','c'],
['d','e','f'],
['g','h','i','j'],
['k','l','m','n','o'],
['p','q','r','s'],
['t','E','E'],
['E','E'],
['E]
]
Here is the code i have tried:
const values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
const halfLen = values.length/2 + 1;
var topArr = [];
for(let i = 0; i < values.length; i ++) {
if(i <= halfLen) {
topArr.push(values[i])
}
}
console.log(topArr)
var filTopArr = [];
for(let i = 0; i <= topArr.length; i ++) {
let prevIndex = i - 1;
if(i === 0) {
filTopArr.push(topArr[i])
} else if(i === 1) {
filTopArr.push(topArr.slice(i, i + i + 1))
} else {
filTopArr.push(topArr.slice(i, i + i ))
}
}
console.log(filTopArr)
my idea here was to separate the array into two different arrays which are going to be the top part that is incrementing in size and the second/bottom part that is going to be decreasing in size.
The above code had this output
[1, [2, 3], [3, 4], [4, 5, 6], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9], [8, 9], [9], []]
Some observations:
The number of strings in the output (including the padding "E" strings) is always a perfect square (1, 4, 9, 16, 25, ...etc)
In order to know how many "E" strings need to be added, we thus need to know which is the least perfect square that is not less than the input size.
The longest (middle) subarray in the output has a size that is the square root of that perfect square.
The number of subarrays is the double of that number minus 1.
This leads to the following implementation:
function diamond(array) {
// Get least perfect square that is not less than the array length
const sqrt = Math.ceil(Math.sqrt(array.length));
const size = sqrt ** 2;
// Pad the array with "E" strings so to reach that perfect square size
const all = [...array, ..."E".repeat(size - array.length)];
const length = 2 * sqrt;
return Array.from({length}, (_, width) => {
return all.splice(0, Math.min(width, length - width));
}).slice(1); // Skip the first subarray that was produced (empty array)
}
// Demo using the two provided examples:
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'];
console.log(diamond(array));
var array = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t'];
console.log(diamond(array));
Here's a recursive version. Note that display is just for presentation purposes.
The only real work is in diamond:
const diamond = (xs, [len = xs.length, up = true, n = 1] = []) => n == 0 ? [] : [
Object .assign (Array (n) .fill ('E'), xs .slice (0, n)),
...diamond (xs .slice (n), up && n * n < len ? [len, true, n + 1] : [len, false, n - 1])
]
const display = (xss) => console .log (`${xss .map (
(xs, i) => `${' '.repeat (Math .abs ((xss .length - 1) / 2 - i) + 1)}${xs .join (' ')
}`) .join ('\n')}`)
const demos = [
['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'],
['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u'],
[1, 2, 3, 4, 5, 6, 7, 8]
]
demos .forEach (array => display (diamond (array)))
.as-console-wrapper {max-height: 100% !important; top: 0}
We track the length of the current string (n, defaulting to 1), the length of the original array (len) , and a boolean flag to tell whether our length is moving up or down (up). We increase n on initial iterations, adding the next n characters from our input as the next subarray. When n hits zero we return an empty array. When n ** n is greater than or equal to len, we switch up to false and start subtracting one from n from then on. The only other necessity is to fill our remaining array with 'E's. We do this with an Object .assign call.
If you want formatted output more like an array literal form, you could use this version of display:
const display = (xss) => console .log (`[\n${xss .map (
(xs, i) => `${' '.repeat (Math .abs ((xss .length - 1) / 2 - i) + 1)}['${xs .join (`','`)
}']`) .join ('\n')}\n]`)
to get output like this:
[
['a']
['b','c']
['d','e','f']
['g','h','i','j']
['k','l','m','n','o']
['p','q','r','s']
['t','u','E']
['E','E']
['E']
]
Note though that this recursion is a little overbearing, with three separate defaulted recursive variables. I would be as likely to go with trincot's solution as this. But it's good to have alternatives.
Related
If I have an array of numbers and I want get the number nearest to average, how can I get that number?
I've tried to sort the array in an ascending order, followed by retrieving the middle element which is the average.
Note: I used Math.floor() in case if the length of the array is odd not even number
const arr = [1, 6, 10, 3, 15, 9, 4, 7];
const arrSorted = arr.sort((a,b)=>a-b);
const nearToAVG = arrSorted[Math.floor(arr.length/2)];
console.log(nearToAVG); // 7
Are there any better ways of getting the number near to the average in array?
Let's dissect this problem. You want the index with the nearest value to the average of the the array indices. To get that you may first calculate the sum of the array. Knowing the sum, you can do a second sweep of the array arr to take the difference of each element from the average and store it in a variable. Lastly, you would update that variable if the difference between the average and the current index is closer to zero than the stored value. By the end of the array, you will have the answer you are looking for.
Here is a simple example of the above:
const arr = [1, 6, 10, 3, 15, 9, 4, 7];
// get average
let sum = 0;
for(let i = 0; i < arr.length; sum += arr[i], i++);
let ave = sum / arr.length; // 6.875
function nearestIdxToAverage(array, average) {
if(!array.length) return 0;
// stores initial difference and gets replaced by index
let nearest = Math.abs(array[0] - average);
for(let i = 0; i < array.length; i++) {
const diff = Math.abs(array[i] - average);
// stores the offset of the diff closest to 0 (relative to the average)
nearest = (diff < nearest)? i: nearest;
}
return nearest;
}
console.log(`average: ${ave}\nnearest idx: ${nearestIdxToAverage(arr, ave)}`);
// average: 6.875
// nearest idx: 7
As I noted in a comment to another answer, this is one of those cases, when you really need to be more precise than "average". The median and the mean are the most common averages, and depending on which you want, you may get different answers. For instance, in [3, 20, 1, 4, 2], the median is 3, but, since the mean is 6, the original value closest to the mean is 4.
This version assumes you want to get the value in the array closest to the arithmetic mean of the numbers:
const closestToMean = (ns, m = ns .reduce ((a, b) => a + b, 0) / ns .length) =>
ns .reduce ((c, n) => Math .abs (n - m) < Math .abs (c - m) ? n : c, Infinity)
console .log (closestToMean ([3, 20, 1, 4, 2]))
console .log (closestToMean ([1, 6, 10, 3, 15, 9, 4, 7]))
We sum the numbers and divide by their length to find the mean, then we fold the list of numbers, keeping at every stage the one closer to that mean.
I would actually prefer to break this up and extract the common helper functions sum, which totals an array of numbers, mean, which uses sum to calculate the arithmetic mean, and minimumBy, which finds the smallest element of an array, according to the result of applying the function supplied to each element. I think this version is much more readable:
const sum = (ns) =>
ns .reduce ((a, b) => a + b, 0)
const mean = (ns) =>
sum (ns) / ns .length
const minimumBy = (fn) => (ns) =>
ns .reduce ((c, n) => fn (n) < fn (c) ? n : c, Infinity)
const closestToMean = (ns, m = mean (ns)) =>
minimumBy (n => Math .abs (n - m)) (ns)
console .log (closestToMean ([3, 20, 1, 4, 2]))
console .log (closestToMean ([1, 6, 10, 3, 15, 9, 4, 7]))
... and we've also happened upon some useful functions to use elsewhere in this program or others.
Another approach to achieve that By using:
reduce to accumulate the sum and divide it by its length to get the average.
map iterate over that array and return each number with its nearByAVG (distance between that number and average).
sort by that property in order ascending and get the first one that has the minimum distance to average.
const arr = [1, 6, 10, 3, 15, 9, 4, 7];
const sum = arr.reduce((acc, curr)=>acc+curr);
const avg = sum/arr.length;
const arrMaped = arr.map(num=>({num,nearByAVG: Math.abs(num-avg)}));
const arrSorted = arrMaped.sort((a,b)=>a.nearByAVG-b.nearByAVG);
console.log(arrSorted[0].num)
You should add all the numbers and divide by the length of the array.
Apart from that, the number the sorted array's center, is not the average of the numbers, just the median.
let numArray=[12,32,134,23,54,345,32,1]; //all elements numbers
let num=0;
for(let number of numArray) {num+=number};
num/=numArray.length
console.log(num)
I am trying to implement the game 2048 using JavaScript. I am using a two-dimensional array to represent the board. For each row, it is represented using an array of integers.
Here I am focused on implementing the merge left functionality i.e. the merge that happens after the user hits left on their keyboard.
Here are a set of test cases that I came up with
const array1 = [2, 2, 2, 0] // [4,2,0,0]
const array2 = [2, 2, 2, 2] // [4,4,0,0]
const array3 = [2, 0, 0, 2] // [4,0,0,0]
const array4 = [2, 2, 4, 16] // [4,4,16,0]
The commented part is the expected results after merge left happened.
Here is my attempt
const arrays = [
[2, 2, 2, 0], // [4,2,0,0]
[2, 2, 2, 2], // [4,4,0,0]
[2, 0, 0, 2], // [4,0,0,0]
[2, 2, 4, 16] // [4,4,16,0]
];
function mergeLeft(array) {
let startIndex = 0
let endIndex = 1
while (endIndex < array.length) {
if (array[startIndex] === array[endIndex]) {
array[startIndex] = array[startIndex] + array[endIndex]
array[endIndex] = 0
startIndex++
}
endIndex++
}
return shift(array, 'left')
}
function shift(array, dir) {
if (dir === 'left') {
for (let i = 0; i < array.length - 1; i++) {
if (array[i] === 0) {
[array[i], array[i + 1]] = [array[i + 1], array[i]]
}
}
}
// omitting when dir === 'right', 'up', 'down' etc.
return array
}
arrays.forEach(a => console.log(mergeLeft(a)));
So the idea here is that I merged the array and then shift the non-zero items to the left.
My current solution is buggy for this particular case - when the array is [2, 2, 2, 2], the output is [4,2,2,0] when the expected output is [4,4,0,0]
I know that my implementation is not elegant either. So I would love to see how this can be implemented in a (much) better way.
By the way I found on code review stack exchange there is a python implementation that seems to be working. However, I don't really know Python nor functional programming paradigm. I would appreciate it if someone can take a look at it and see if how this can be translated into JavaScript
I think a recursive version is simplest here:
const zeroFill = xs =>
xs .concat ([0, 0, 0, 0]) .slice (0, 4)
const shift = ([n0, n1, ...ns]) =>
n0 == undefined
? []
: n0 == 0
? shift ([n1, ...ns])
: n1 == 0
? shift ([n0, ...ns])
: n0 == n1
? [n0 + n1, ... shift (ns)]
: [n0, ...shift ([n1, ... ns])]
const shiftLeft = (ns) =>
zeroFill (shift (ns))
const arrays = [[2, 2, 2, 0], [2, 2, 2, 2], [2, 0, 0, 2], [2, 2, 4, 16], [0, 8, 2, 2], [0, 0, 0, 0]];
arrays .forEach (
a => console.log(`${JSON .stringify (a)}: ${JSON .stringify (shiftLeft (a))}`)
)
Our basic shift is wrapped with zeroFill, which adds trailing zeros to the the array, to make it four long.
The main function is shift, which does a shift-left of a row, but if I were to build a complete 2048, I would used this for all shifts, simply translating the directions to the indices required. It works like this:
If our array is empty, we return an empty array
If the first value is zero, we ignore it and continue with the rest of the array
If the second value is zero, we remove it and recur with the remainder (including the first value)
If the first two values are equal, we combine them for the first spot and recur on the remainder
Otherwise, we keep the first value, and then recur on everything else (including the second value)
Although we could remove the wrapper, merging the zero-filling into the main function, so that, for instance in the second case, instead of returning shift([n1, ...ns]) we would return zeroFill(shift([n1, ...ns])). But that would mean calling the zero-fill several times for no good reason.
Update
A comment asked for clarification on how I would use this for shifting boards in all directions. Here is my first thought:
// utility functions
const reverse = (xs) =>
[...xs] .reverse();
const transpose = (xs) =>
xs [0] .map ((_, i) => xs .map (r => r[i]))
const rotateClockwise = (xs) =>
transpose (reverse (xs))
const rotateCounter = (xs) =>
reverse (transpose (xs))
// helper functions
const shift = ([n0, n1, ...ns]) =>
n0 == undefined
? []
: n0 == 0
? shift ([n1, ...ns])
: n1 == 0
? shift ([n0, ...ns])
: n0 == n1
? [n0 + n1, ... shift (ns)]
: [n0, ... shift ([n1, ... ns])]
const shiftRow = (ns) =>
shift (ns) .concat ([0, 0, 0, 0]) .slice (0, 4)
// main functions
const shiftLeft = (xs) =>
xs .map (shiftRow)
const shiftRight = (xs) =>
xs .map (x => reverse (shiftRow (reverse (x))))
const shiftUp = (xs) =>
rotateClockwise (shiftLeft (rotateCounter (board)))
const shiftDown = (xs) =>
rotateClockwise (shiftRight (rotateCounter (board)))
// sample data
const board = [[4, 0, 2, 0], [8, 0, 8, 8], [2, 2, 4, 8], [0, 0, 4, 4]]
// demo
const display = (title, xss) => console .log (`----------------------\n${title}\n----------------------\n${xss .map (xs => xs .map (x => String(x).padStart (2, ' ')) .join(' ')).join('\n')}`)
display ('original', board)
display ('original shifted left', shiftLeft (board))
display ('original shifted right', shiftRight (board))
display ('original shifted up', shiftUp (board))
display ('original shifted down', shiftDown (board))
.as-console-wrapper {max-height: 100% !important; top: 0}
We start with function to reverse a copy of an array, and to transpose a grid over the main diagonal (northwest to southeast). We combine those two in order to create functions to rotate a grid clockwise and counter-clockwise. Then we include the function discussed above, slightly renamed, and with the zero-fill helper inlined.
Using these we can now write our directional shift function fairly easily. shiftLeft just maps shiftRow over the rows. shiftRight first reverses the rows, calls shiftLeft and then reverses them again. shiftUp and shiftDown rotate the board counter-clockwise call shiftLeft and shiftRight, respectively, and then rotates the board clockwise.
Note that none of these main functions mutate your data. Each returns a new board. That is one of the most important tenets of functional programming: treat data as immutable.
This is not a full 2048 system. It doesn't randomly add new 2s or 4s to the board, nor does it have any notion of a user interface. But I think it's probably a reasonably solid core for a functional version of the game..
You can try this.
const arrays = [
[2, 2, 2, 0], // [4,2,0,0]
[2, 2, 2, 2], // [4,4,0,0]
[2, 0, 0, 2], // [4,0,0,0]
[2, 2, 4, 16] // [4,4,16,0]
];
function shiftLeft(array) {
op = []
while(array.length!=0){
let v1 = array.shift();
while(v1==0 && array.length>0){
v1 = array.shift();
}
if(array.length==0){
op.push(v1);
}else{
let v2 = array.shift();
while(v2==0 && array.length>0){
v2 = array.shift();
}
if(v1==v2){
op.push(v1+v2);
}else{
op.push(v1);
array.unshift(v2);
}
}
}
while(op.length!=4){
op.push(0);
}
return op
}
arrays.forEach(a => console.log(shiftLeft(a)));
Here is a function that performs the merge and shift in one loop:
function mergeLeft(array) {
let startIndex = 0;
for (let endIndex = 1; endIndex < array.length; endIndex++) {
if (!array[endIndex]) continue;
let target = array[startIndex];
if (!target || target === array[endIndex]) { // shift or merge
array[startIndex] += array[endIndex];
array[endIndex] = 0;
} else if (startIndex + 1 < endIndex) {
endIndex--; // undo the next for-loop increment
}
startIndex += !!target;
}
return array;
}
// Your tests:
const arrays = [
[2, 2, 2, 0], // [4,2,0,0]
[2, 2, 2, 2], // [4,4,0,0]
[2, 0, 0, 2], // [4,0,0,0]
[2, 2, 4, 16] // [4,4,16,0]
];
for (let array of arrays) console.log(...mergeLeft(array));
Explanations
The for loop increments the endIndex from 1 to 3 included. This index represents a potential value that needs to shift and/or merge.
If that index refers to an empty slot (value is 0), then nothing needs to happen with it, and so we continue with the next iteration of the loop.
So now we are in the case where endIndex refers to a non-zero value. There are two cases where something needs to happen with that value:
The value at startIndex is zero: in that case the value at endIndex must move to startIndex
The value at startIndex is equal to that at endIndex: in that case the value at endIndex must also move to startIndex, but adding to it what was already there.
These cases are very similar. In the first case we could even say that the value at endIndex is added to the one at startIndex since the latter is zero. So these two cases are handled in one if block.
If we are not in either of these two cases then we know that the value at startIndex is non-zero and different from the one at endIndex. In that case we should leave the value at startIndex unaltered and just move on. However, we should reconsider the value of this same endIndex again in the next iteration, as it might need to move still. So that is why we do endIndex-- so to neutralise the loop's endIndex++ that will happen one instant later.
There is one case where we do want to go to the next endIndex: that is when startIndex would become equal to endIndex: that should never be allowed in this algorithm.
Finally, startIndex is incremented when it originally had a non-zero value. However, if it was zero at the start of this iteration, it should be reconsidered in the next iteration of the loop. So then we do not add 1 to it. startIndex += !!target is just another way for doing:
if (target > 0) startIndex++;
I'm trying to solve this question on LeetCode:
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note: The number of elements initialized in nums1 and nums2 are m and n respectively.
You may assume that nums1 has enough space (size that is equal to m + n) to hold additional elements from nums2.
I ended up with coming up with this code:
var merge = function(nums1, m, nums2, n) {
var nums = [];
nums1.length = m;
nums2.length = n;
nums = nums.concat(nums1);
console.log(nums);
nums = nums.concat(nums2);
console.log(nums);
nums = nums.sort();
console.log(nums);
return nums;
}
This is what the 'run code' says:
Your input
[1,2,3,0,0,0]
3
[2,5,6]
3
stdout
[ 1, 2, 3 ]
[ 1, 2, 3, 2, 5, 6 ]
[ 1, 2, 2, 3, 5, 6 ]
Output:
[1,2,3]
Expected
[1,2,2,3,5,6]
(an image version if the quotes weren't clear)
When I'm console.logging the array, the answer is correct but for some reason returning the array gives a completely different output
Can anyone help in this?
I think the hint here is that nums1 is big enough to hold n+m values. So the way to solve this problem is to work backwards through both arrays, filling the empty space in nums1 as you go. So for example, for the first iteration of the loop, you would compare nums1[n-1] and nums2[m-1] and put whichever is larger into nums1[n+m-1]. You then continue this for as long as you have values in either array, copying exclusively from the other if one runs out:
const merge = function(nums1, m, nums2, n) {
n--; m--;
for (let i = m + n + 1; i >= 0; i--) {
nums1[i] = (m < 0 || n >= 0 && nums2[n] > nums1[m]) ? nums2[n--] : nums1[m--];
}
return nums1;
}
console.log(merge([1, 2, 3, 0, 0, 0], 3, [2, 5, 6], 3));
This code is O(n) (as compared to your sort which is O(nlogn)) and requires no additional space.
Question
You are going to be given an array of integers. Your job is to take that array and find an index N where the sum of the integers to the left of N is equal to the sum of the integers to the right of N. If there is no index that would make this happen, return -1.
For example:
Let's say you are given the array {1,2,3,4,3,2,1}: Your function will return the index 3, because at the 3rd position of the array, the sum of left side of the index ({1,2,3}) and the sum of the right side of the index ({3,2,1}) both equal 6.
Answer
function findEvenIndex(arr){
for(let i = 0; i <arr.length; i++){
let arr1 = arr.slice(0, (arr[i] - 1));
let arr2 = arr.slice((arr[i] + 1),);
let arr11 = arr1.reduce((total, item)=>{
return total + item;
}, 0);
let arr22 = arr2.reduce((total, item)=>{
return total + item;
}, 0);
if(arr11 === arr22){
return arr[i];
}
}
return -1;
}
console.log(findEvenIndex([1, 2, 3, 4, 3, 2, 1]))
console.log(findEvenIndex([1, 100, 50, -51, 1, 1]))
console.log(findEvenIndex([1, 2, 3,4,5,6]))
I can't see an error here, but it yields incorrect results. Any ideas?
You have this part:
let arr1 = arr.slice(0, (arr[i] - 1));
let arr2 = arr.slice((arr[i] + 1),);
This is incorrect: arr[i]. That is a value, eg in [2,4,6,8,10] arr[3]==8. You want to slice on the index itself:
let arr1 = arr.slice(0, i - 1);
let arr2 = arr.slice(i + 1,);
Please note: There is another error in the two lines :) I leave that to you. Hint: you're now slicing two values out of the array instead of one. Perform the following code in your head first, then somewhere where you verify your results.
let arr = [0,1,2,3,4]
let x = 2;
console.log(arr.slice(0, x - 1));
console.log(arr.slice(x + 1,));
You could also use the array method findIndex, which, we shouldn't be surprised to learn, finds an index in an array subject to a certain condition.
const sum = (ns) =>
ns .reduce ((total, n) => total + n, 0)
const findBalancedIndex = (ns) =>
ns .findIndex ((_, i) => sum (ns.slice (0, i)) === sum (ns.slice (i + 1)))
console .log (findBalancedIndex ([1, 2, 3, 4, 3, 2, 1]))
console .log (findBalancedIndex ([1, 100, 50, -51, 1, 1]))
console .log (findBalancedIndex ([1, 2, 3, 4, 5, 6]))
Here we include a simple helper function to find the sum of an array, and then we pass a function to findIndex which uses it twice on the elements before the index and those after it. We use the second parameter of the callback function, the index to do this. This means we are skipping the first parameter altogether, and rather than naming it with something like n, we use the somewhat common convention of calling it _, signalling a placeholder we won't use. Note that you don't need to subtract one from the right-hand boundary of slice, since that boundary value is already excluded. And of course, others have pointed out that you need to slice to the index and not the array value at that index.
This finds the first correct index. You would have to use a different technique if you wanted to find all such indices. (That it's possible to have more than one should be clear from arrays like [1, 2, 3, 0, 0, 0, 0, 3, 2, 1] -- the indices for all those 0s would work.)
you return arr[i] when you need to return just i
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