Select and pair leftmost and rightmost elements in an array - javascript

I have an array e.g [0,1,2,3,4,5] the length will always be even.
How do I select and pair starting from the leftmost and rightmost elements all the way to the center position?
In the above array it should result [[0,5],[1,4],[2,3]]
I have tried this so far... here
const arr = [0,1,2,3,4,5]
const result = []
const possibleMatches = arr.length / 2
for (let x = 0; x < possibleMatches; x++) {
result.push([arr[x], arr[arr.length - x - 1]])
}
console.log(result)
//[ [ 0, 5 ], [ 1, 4 ], [ 2, 3 ] ]
However, I think they must be better approach than for loop? like using one line arrow function e.t.c?

You can split the array in half (with Array.splice), then map over the array and use the same logic as you did in your for loop to get the item on the "right" side:
const arr = [0, 1, 2, 3, 4, 5]
const result = arr.splice(0, arr.length / 2).map((e, i) => [e, arr[arr.length - i - 1]])
console.log(result)

You can use Array.from() to create an array with half the size of the original, and take the values from the start and end of the original array:
const arr = [0,1,2,3,4,5]
const result = Array.from(
{ length: Math.ceil(arr.length / 2) },
(_, i) => [arr[i], arr[arr.length - 1 - i]]
)
console.log(result)
You can use Array.at() (if supported) to reduce the need for length calculations:
const arr = [0,1,2,3,4,5]
const result = Array.from(
{ length: Math.ceil(arr.length / 2) },
(_, i) => [arr.at(i), arr.at(-i-1)]
)
console.log(result)

take the second half of the array, flip it and merge it with the first half.
here's the one liner.
const arr = [0,1,2,3,4,5]
const result = arr.slice(arr.length / 2 * -1).reverse().map((element, index) => [arr[index],element])
const possibleMatches = arr.length / 2
console.log(result)

Using a simple for loop iterating from both ends
const arr = [0, 1, 2, 3, 4, 5];
let res = [],
i = 0,
j = arr.length - 1;
for (; i < j; i++, j--) {
res.push([arr[i], arr[j]]);
}
console.log(JSON.stringify(res));
or while
const arr = [0, 1, 2, 3, 4, 5];
const result = [];
while (arr.length > 1) {
result.push([arr.shift(), arr.pop()]);
}
console.log(JSON.stringify(result));

Related

How to merge an array with another one

I have a challenge to complete where I'm given an array [-1,4,-3,5,6,9,-2] and I need to get a new array that sorts the numbers in this order: [firstGreatest, firstLowest, secondGreatest, secondLowest ...and so on]. The negative and positive numbers may be different amount, as in 4 positive, 2 negative.
This is what I tried so far, but cannot think of a better solution.
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = ary.sort((a, b) => a - b)
const highest = sorted.filter(num => num > 0).sort((a, b) => b - a)
const lowest = sorted.filter(num => num < 0).sort((a, b) => b - a)
let copy = highest
for (let i = 0; i < highest.length; i++) {
for (let j = i; j < lowest.length; j++) {
if ([i] % 2 !== 0) {
copy.splice(1, 0, lowest[j])
}
}
}
}
console.log(arr)
someArray(arr)
console.log(arr)
You can easily solve this problem with two pointers algorithm.
O(n log n) for sorting
O(n) for add the value in result.
Take two-variable i and j,
i points to the beginning of the sorted array
j points to the end of the sorted array
Now just add the value of the sorted array alternatively in final result
let arr = [-1, 2, -5, 3, 4, -2, 6];
function someArray(ary) {
const sorted = arr.sort((a, b) => b - a);
// declaration
const result = [];
let i = 0,
j = sorted.length - 1,
temp = true;
// Algorithm
while (i <= j) {
if (temp) {
result.push(sorted[i]);
i++;
} else {
result.push(sorted[j]);
j--;
}
temp = !temp;
}
return result;
}
console.log(someArray(arr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could sort the array and pop or shift until you have no more items.
function greatestLowest(array) {
let temp = [...array].sort((a, b) => a - b),
m = 'shift',
result = [];
while (temp.length) result.push(temp[m = { pop: 'shift', shift: 'pop' }[m]]());
return result;
}
console.log(...greatestLowest([-1, 2, -5, 3, 4, -2, 6]));
The general idea is to sort the array (highest to lowest) then pick the first and the last element until the array is empty. One way of doing it could be:
const input = [-1, 2, -5, 3, 4, -2, 6];
function someArray(arr) {
// sort the original array from highest to lowest
const sorted = arr.sort((a, b) => b - a);
const output = []
while (sorted.length > 0) {
// remove the first element of the sorted array and push it into the output
output.push(...sorted.splice(0, 1));
// [check to handle arrays with an odd number of items]
// if the sorted array still contains items
// remove also the last element of the sorted array and push it into the output
if (sorted.length > 0) output.push(...sorted.splice(sorted.length - 1, 1))
}
return output;
}
// test
console.log(`input: [${input.join(',')}]`);
console.log(`input (sorted desc): [${input.sort((a, b) => b - a).join(',')}]`)
console.log(`output: [${someArray(input).join(',')}]`);
This is a simple and a shorter method:
function makearray(ar) {
ar = points.sort(function(a, b) {
return b - a
})
let newarray = []
let length = ar.length
for (let i = 0; i < length; i++) {
if (i % 2 == 0) {
newarray.push(ar[0])
ar.splice(0, 1)
} else {
newarray.push(ar[ar.length - 1])
ar.splice(ar.length - 1, 1)
}
}
return newarray
}
const points = [-1, 2, -5, 3, 4, -2, 6]
console.log(makearray(points))

How to do I convert a single array into an array of arrays of two members each [duplicate]

This question already has answers here:
Split array into chunks
(73 answers)
Closed 2 years ago.
let flattened = [[0, 1], [2, 3], [4, 5]].reduce(
function(accumulator, currentValue) {
return accumulator.concat(currentValue)
},
[]
)
// flattened is [0, 1, 2, 3, 4, 5]
How do I reverse this?
I have this array [0, 1, 2, 3, 4, 5] and I want to convert to this one [ [0, 1], [2, 3], [4, 5] ];
const result = [0, 1, 2, 3, 4, 5].reduce(
(acc, val) => {
if (acc[acc.length - 1].length < 2) {
acc[acc.length - 1].push(val);
} else {
acc.push([val]);
}
return acc;
},
[[]],
);
console.log(result);
This snippet creates an array with a number of indexes, then maps the starting index of each division and uses that index in the next map to take a slice of the original array based on the given size.
const value = [0, 1, 2, 3, 4, 5];
const arrayChunks = (array, size) => Array(Math.ceil(array.length / size)).fill()
.map((entry, index) => index * size)
.map(begin => array.slice(begin, begin + size));
let result = arrayChunks(value, 2);
console.log(result);
Or, more imperative approach
function convert(arr) {
const nextArray = [];
for (let i = 0; i < arr.length; i += 2) {
// Handle case where there is no pair for the element
// Can be removed if not required
const isLastElement = arr.length === i + 1;
if (isLastElement) {
nextArray.push([arr[i]]);
} else {
nextArray.push([arr[i], arr[i + 1]]);
}
}
return nextArray;
}
const result1 = convert([1,2,3,4]);
const result2 = convert([1,2,3]);
console.log('Even', result1);
console.log('Odd', result2);
Another way with foreach:
const data = [0,1,2,3,4,5]
let subArray = [];
let result = []
data.forEach((val, i) => {
subArray.push(val);
if(subArray.length == 2 || i == (data.length - 1)) {
result.push(subArray);
subArray = [];
}
})
console.log(result)

JS Arrays — Reorganize 1D Array into 2D Array of N Groups Placing Values Sequentially

I've tried a few approaches to this but I can't seem to come up with a viable solution...
In short, I want to create a function to transform a 1D array of any length into a new 2D array of a specific length. Each value from the 1D array should be sequentially placed into each child-array up to the specified length, then start back at the first child-array.
Input / Desired Output Below:
function groupArray(arr, numberOfGroups) {
...
};
// Input Data
const items = [1, 2, 3, 4, 5, 6, 7];
const size = 3;
console.log(groupArray(items, size));
// Expected Output
// [[1, 4, 7], [2, 5], [3, 6]]
You could take the reminder operator % with index and wanted size of the array for getting the right target array.
const
groupArray = (array, size) => array.reduce((result, value, index) => {
const target = index % size;
if (!result[target]) result[target] = [];
result[target].push(value);
return result;
}, []);
console.log(groupArray([1, 2, 3, 4, 5, 6, 7], 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using nested for
function groupArray(arr, numberOfGroups) {
var result = []
for (var i = 0; i < numberOfGroups; i++) {
var subarr = []
for (var j = i; j < arr.length; j += numberOfGroups) {
subarr.push(arr[j])
}
result.push(subarr)
}
return result
};
// Input Data
const items = [1, 2, 3, 4, 5, 6, 7];
const size = 3;
console.log(groupArray(items, size));
Also something like this would do it,
you'd not need to mutate any input
const chunkify = (step, list) => list.reduce(
([chunk, rest], item, i) => {
const pick = i % step === 0;
return [
chunk.concat(pick ? item : []),
rest.concat(pick ? [] : item),
];
},
[[], []],
);
const group = (step, list, result = []) => {
if (!list.length) { return result; }
const [chunk, rest] = chunkify(step, list);
return group(step - 1, rest, [...result, chunk]);
};
const data = [1, 2, 3, 4, 5, 6, 7];
const step = 3;
console.log(
group(step, data),
);
Have method next, each call will return next index and when limit reaches numberOfGroups reset the index 0. (in this case, it will be like 0, 1, 2, 0, 1, 2....)
With this method, can easily push to corresponding output sub array.
const groupArray = (arr, numberOfGroups) => {
const output = Array.from({ length: numberOfGroups }, () => []);
const next = index => index % numberOfGroups;
arr.forEach((num, i) => output[next(i)].push(num));
return output;
};
// Input Data
const items = [1, 2, 3, 4, 5, 6, 7];
const size = 3;
console.log(groupArray(items, size));

How to get the index of the 5 smallest values in an array?

I am trying to get the indexes of the 5 smallest values in an array.
I've tried the code below, however it gives the error: Math.min.apply(...).indexOf is not a function. I'm just not sure what I can use as an alternative?
var smallest = [];
for (var i = 0, length = distances.length; i < length; i++) {
var min = Math.min.apply(null,distances).indexOf();
if (smallest.length <= 5) {
smallest.push(min);
}
console.log(smallest);
}
Thanks!
You could get the keys, sort them with the values and take the top five.
var indices = [...distances.keys()]
.sort((a, b) => distances[a] - distances[b])
.slice(0, 5);
You can use Object.entries() to get [index, value] pairs that you can now sort by value to get the order.
const distances = [1, 4, 8, 3, 3, 5, 9, 0, 4, 2];
const indices = Object.entries(distances)
.sort(([,a],[,b]) => a - b)
.map(([index]) => +index)
.slice(0, 5)
console.log(indices);
Nina's version is better :)
You could add an index to each element, sort the data in ascending order, then splice the first 5 values:
const data = [1, 4, 8, 3, 3, 5, 9, 0, 4, 2]
const indices = data.map((e,i) => [e, i])
.sort()
.splice(0,5)
.map(([,el]) => el)
console.log(indices)

Sequentially Pairing Items in an Array

Given an array, [1, 2, 3, 4, 5], what is the most efficient method for pairing up each of the items sequentially, like so: [[1,2], [2,3], [3,4], [4,5]]?
I've been trying to use the reduce method but to no avail and want something elegant.
Use simple for loop
var data = [1, 2, 3, 4, 5];
var res = [];
for (var i = 0; i < data.length-1; i++) {
res.push(data.slice(i, i+2));
}
console.log(res);
With Array#reduce method
console.log(
[1, 2, 3, 4, 5].reduce(function(a, b, i) {
if (i == 1) return [[a, b]];
a.push([a[a.length - 1][1], b]);
return a
})
)
With Array#reduce method with initial value as empty array
console.log(
[1, 2, 3, 4, 5].reduce(function(a, b, i, arr) {
arr[i + 1] !== undefined && a.push([b, arr[i + 1]])
return a
}, [])
)
To answer the "elegant" bit... ;)
let pairwise = function *(it) {
var
a = it[Symbol.iterator](),
b = it[Symbol.iterator]();
b.next();
for (var x of b) {
yield [a.next().value, x]
}
};
console.log(Array.from(pairwise([1,2,3,4,5])))
Using lodash for given array:
var result = _.chunk( _.sortBy(array.concat(_.slice(array, 1, array.length - 1))), 2);
Check jsfiddle
So if array = [1,2,3,4,5] we have steps:
_.slice(array, 1, array.length - 1)
// = [2,3,4]
array.concat(_.slice(array, 1, array.length - 1)
// = [1,2,3,4,5].concat([2,3,4]) = [1,2,3,4,5,2,3,4]
_.sortBy(array.concat(_.slice(array, 1, array.length - 1))
// _sortBy([1,2,3,4,5,2,3,4]) = [1,2,2,3,3,4,4,5]
_.chunk( _.sortBy(array.concat(_.slice(array, 1, array.length - 1))), 2)
// _chunk([1,2,2,3,3,4,4,5],2) = [[1,2],[2,3],[3,4],[4,5]]
Another short solution using Array.forEach and Array.push functions:
var arr = [1, 2, 3, 4, 5], pairs = [];
arr.forEach((v, k, arr) => arr[k+1] && pairs.push([v, arr[k+1]]));
console.log(JSON.stringify(pairs)); // [[1,2],[2,3],[3,4],[4,5]]
Using reduce:
const res = [1, 2, 3, 4, 5].reduce(
([b, acc], a) => [a, acc.concat([[b, a]])]
, [null, []])[1].slice(1)
console.log(res)
The seed of reduce is a tuple of two items: [null, []]. null represents the current element in the array and [] is the result.
In the first iteration of reduce:
([b, acc], a) => ... b = null and acc = []
The function produces a new tuple, the first item in the tuple is the current element of the array and the second item is the result. In the second iteration:
([b, acc], a) => ..., b = 1 and acc = [[null, 1]]
The second iteration will add (concat) [1, 2] to the result (acc).
In the third iteration:
([b, acc], a) => ..., b = 2 and acc = [[null, 1], [1, 2]]
And so on so forth:
const trace = (x, y) => {
console.log(x);
return y;
}
const json = x => JSON.stringify(x)
const res = [1, 2, 3, 4, 5].reduce(
([b, acc], a) => trace(
`a = ${a}, b = ${b} acc = ${json(acc)} ++ ${json([[b, a]])}`
, [a, acc.concat([[b, a]])]
)
, [null, []]) // seed
// the result is a tuple `[currentElement, finalResult], we extract finalResult here
[1]
// -1 element of the original array was null (check the seed), let's remove it from the result
.slice(1)
console.log(res)
We can think about the problem another way: we are kind of joining the elements of the same array with each other into tuples. Using Ramda zip function is elegant but has a performance tradeoff because we go thru the list twice:
const arr = [1, 2, 3, 4, 5]
const res = R.zip(arr, R.drop(1, arr))
console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.21.0/ramda.min.js"></script>
Reduce is most elegant way to do that.
[1,2,3,4,5].reduce((a,b,c) => {
a.push([c,b]);
return a;
}, [])

Categories