I am trying to write a Javascript function that takes an array, page_size and page_number as parameters and returns an array that mimics paginated results:
paginate: function (array, page_size, page_number) {
return result;
}
so for example when:
array = [1, 2, 3, 4, 5],
page size = 2,
page_number = 2,
the function should return: [3, 4].
Any ideas would be appreciated.
You can use Array.prototype.slice and just supply the params for (start, end).
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
console.log(paginate([1, 2, 3, 4, 5, 6], 2, 2));
console.log(paginate([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 4, 1));
Here's a solution with reduce():
function paginate (arr, size) {
return arr.reduce((acc, val, i) => {
let idx = Math.floor(i / size)
let page = acc[idx] || (acc[idx] = [])
page.push(val)
return acc
}, [])
}
let array = [1, 2, 3, 4, 5]
let page_size = 2
let pages = paginate(array, page_size)
console.log(pages) // all pages
console.log(pages[1]) // second page
It returns an array of pages so you can get a certain page, or loop through all of them.
I saw an example above that did this correctly (kind of) and wanted to expand on it.
This was the example.
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
There are a few things wrong with this.
1.) If the page_number is 0 then it will try and set the starting split at -1 * page_size which returns an empty array. So the minimum value of the page_number attr should be 1, never anything less unless you handle that case in the function.
2.) The starting and ending index of the split are the same. Because of this, you get back an empty array. So the split should be:
return array.split(page_number * page_size, page_number * page_size + page_size)
const myArray = [1,2,3,4,5,6,7,8,9,10];
const paginateBad1 = (array, page_size, page_number) => {
return array.slice((page_number - 1) * page_size, page_number * page_size);
};
const paginateBad2 = (array, page_size, page_number) => {
return array.slice(page_number * page_size, page_number * page_size);
};
const paginateGood = (array, page_size, page_number) => {
return array.slice(page_number * page_size, page_number * page_size + page_size);
};
console.log("Bad 1", paginateBad1(myArray, 2, 0));
console.log("Bad 2", paginateBad2(myArray, 2, 1));
console.log("Good", paginateGood(myArray, 2, 1));
Another aproach that you can utilize, is using .filter, look:
const paginate = function (array, index, size) {
// transform values
index = Math.abs(parseInt(index));
index = index > 0 ? index - 1 : index;
size = parseInt(size);
size = size < 1 ? 1 : size;
// filter
return [...(array.filter((value, n) => {
return (n >= (index * size)) && (n < ((index+1) * size))
}))]
}
var array = [
{id: "1"}, {id: "2"}, {id: "3"}, {id: "4"}, {id: "5"}, {id: "6"}, {id: "7"}, {id: "8"}, {id: "9"}, {id: "10"}
]
var transform = paginate(array, 2, 5);
console.log(transform) // [{"id":"6"},{"id":"7"},{"id":"8"},{"id":"9"},{"id":"10"}]
You can use Array.filter() with the help of its second parameter (the index of the current element being processed in the array).
You'll also need the currently selected page and the number of items per page to display, so you can find the minimum and maximum index of the elements needed.
const indexMin = selectedPage * elementsPerPage;
const indexMax = indexMin + elementsPerPage;
const paginatedArray = arrayToPaginate.filter(
(x, index) => index >= indexMin && index < indexMax
);
Updating the selectedPage and/or the elementsPerPage value will allow to return the correct items to display.
The use of Array#slice is the expected answer.
Here I use Symbol.iterator to create an iterable.
const arr = [1,2,3,4,5,6,7,8,9,10]
function page({arr, pageSize, pageNumber}) {
const start = pageSize*(pageNumber-1)
const end = pageSize*pageNumber
return {
*[Symbol.iterator]() {
for(let i = start; i < arr.length && i < end; i++) {
yield arr[i]
}
}
}
}
console.log([...page({arr, pageSize: 5, pageNumber: 2})])
Hey I'm sorry I'm a bit late but we can use the Array.splice(start, end) method except this is much simpler
const page = 2
const step = 2;
const start = page * step - step;
const end = start + step;
const array = [1,2,3,4,5,6]
console.log(array.splice(start, end))
Here is another variation using Array.from with Array.slice
const paginate = (array, n) => {
const pageSize = Math.ceil(array.length / n);
return Array.from({ length: pageSize }, (_, index) => {
const start = index * n;
return array.slice(start, start + n);
});
};
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
var arr = [1, 2, 3, 4, 5, 6]
const options = {
//page: parseInt(req.query.page) || 1,
page:1,
limit:10
//limit: parseInt(req.query.limit) || 10,
//customLabels: servCustomLabels,
};
let prev_page = 0;
let next_page = 0;
let h_p_p = null;
let h_n_p = null;
let page_count = Math.ceil((arr.length / options.limit));
if (options.page >= page_count ){ // 2 3
next_page = 0;
}
if(options.page >= 1 && options.page < page_count ){
next_page = options.page + 1;
h_n_p = true;
}else{
next_page = 0;
h_n_p = false;
}
if(options.page <= 1 ){
prev_page =0;
h_p_p = false;
}else{
prev_page = options.page -1 ;
h_p_p = true;
}
console.log(paginate(arr, 2, 2));
console.log({paginator: {
totalDocs: arr.length,
perPage: options.limit,
pageCount: page_count,
currentPage: options.page,
//slNo: 2,
hasPrevPage: h_p_p,
hasNextPage: h_n_p,
prev: prev_page,
next: next_page
}})
function paginate(arr, PerPage) {
let map = {};
let startPage = 1;
arr.forEach((current) => {
if (map[startPage] && map[startPage].length < PerPage) {
map[startPage].push(current);
}
if (!map[startPage]) {
map[startPage] = [current];
}
if (map[startPage] && map[startPage].length >= PerPage) {
startPage++;
}
});
return map;
}
you will find an example on this link
The example below is using iter-ops library (I'm the author).
// our inputs...
const array = [1, 2, 3, 4, 5];
const pageSize = 2;
const pageIndex = 1;
The most efficient way is to process an array as an iterable, so you go through it once.
If you never need other pages, then the fastest way is like this:
import {pipe, skip, page} from 'iter-ops';
const p = pipe(
array,
skip(pageSize * pageIndex), // skip pages we don't want
page(pageSize) // create the next page
).first;
console.log(p); //=> [3, 4]
And if you do need other pages, then you can do:
const p = pipe(
array,
page(pageSize), // get all pages
skip(pageIndex) // skip pages we don't want
).first;
console.log(p); //=> [3, 4]
And in case you need to do further processing:
const i = pipe(
array,
page(pageSize), // get all pages
skip(pageIndex), // skip pages we don't want
take(1), // take just one page
// and so on, you can process it further
);
console.log([...i]); //=> [[3, 4]]
A simple solution using filter:
function paginate(array, pageIndex, pageSize) {
const first = pageIndex * pageSize
const last = (pageIndex * pageSize) + pageSize
return array.filter((_, index) => {
return first <= index && index < last
})
}
for (let pageNum = 1; pageNum <= totalPagesCount; pageNum++){
....
const chunk = articles.slice(
(pageNum - 1) * pageSizeNumbered,
pageNum * pageSizeNumbered,
);
.....
}
I'd go with something like this;
const paginateArray = (array, pageNumber, pageSize) => {
const page = array.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
return page;
};
const array = [1, 2, 3, 4, 5];
const pageSize = 2;
const pageNumber = 2;
console.log(paginateArray(array, pageNumber, pageSize));
Related
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))
I am trying to write a Javascript function that takes an array, page_size and page_number as parameters and returns an array that mimics paginated results:
paginate: function (array, page_size, page_number) {
return result;
}
so for example when:
array = [1, 2, 3, 4, 5],
page size = 2,
page_number = 2,
the function should return: [3, 4].
Any ideas would be appreciated.
You can use Array.prototype.slice and just supply the params for (start, end).
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
console.log(paginate([1, 2, 3, 4, 5, 6], 2, 2));
console.log(paginate([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 4, 1));
Here's a solution with reduce():
function paginate (arr, size) {
return arr.reduce((acc, val, i) => {
let idx = Math.floor(i / size)
let page = acc[idx] || (acc[idx] = [])
page.push(val)
return acc
}, [])
}
let array = [1, 2, 3, 4, 5]
let page_size = 2
let pages = paginate(array, page_size)
console.log(pages) // all pages
console.log(pages[1]) // second page
It returns an array of pages so you can get a certain page, or loop through all of them.
I saw an example above that did this correctly (kind of) and wanted to expand on it.
This was the example.
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
There are a few things wrong with this.
1.) If the page_number is 0 then it will try and set the starting split at -1 * page_size which returns an empty array. So the minimum value of the page_number attr should be 1, never anything less unless you handle that case in the function.
2.) The starting and ending index of the split are the same. Because of this, you get back an empty array. So the split should be:
return array.split(page_number * page_size, page_number * page_size + page_size)
const myArray = [1,2,3,4,5,6,7,8,9,10];
const paginateBad1 = (array, page_size, page_number) => {
return array.slice((page_number - 1) * page_size, page_number * page_size);
};
const paginateBad2 = (array, page_size, page_number) => {
return array.slice(page_number * page_size, page_number * page_size);
};
const paginateGood = (array, page_size, page_number) => {
return array.slice(page_number * page_size, page_number * page_size + page_size);
};
console.log("Bad 1", paginateBad1(myArray, 2, 0));
console.log("Bad 2", paginateBad2(myArray, 2, 1));
console.log("Good", paginateGood(myArray, 2, 1));
Another aproach that you can utilize, is using .filter, look:
const paginate = function (array, index, size) {
// transform values
index = Math.abs(parseInt(index));
index = index > 0 ? index - 1 : index;
size = parseInt(size);
size = size < 1 ? 1 : size;
// filter
return [...(array.filter((value, n) => {
return (n >= (index * size)) && (n < ((index+1) * size))
}))]
}
var array = [
{id: "1"}, {id: "2"}, {id: "3"}, {id: "4"}, {id: "5"}, {id: "6"}, {id: "7"}, {id: "8"}, {id: "9"}, {id: "10"}
]
var transform = paginate(array, 2, 5);
console.log(transform) // [{"id":"6"},{"id":"7"},{"id":"8"},{"id":"9"},{"id":"10"}]
You can use Array.filter() with the help of its second parameter (the index of the current element being processed in the array).
You'll also need the currently selected page and the number of items per page to display, so you can find the minimum and maximum index of the elements needed.
const indexMin = selectedPage * elementsPerPage;
const indexMax = indexMin + elementsPerPage;
const paginatedArray = arrayToPaginate.filter(
(x, index) => index >= indexMin && index < indexMax
);
Updating the selectedPage and/or the elementsPerPage value will allow to return the correct items to display.
The use of Array#slice is the expected answer.
Here I use Symbol.iterator to create an iterable.
const arr = [1,2,3,4,5,6,7,8,9,10]
function page({arr, pageSize, pageNumber}) {
const start = pageSize*(pageNumber-1)
const end = pageSize*pageNumber
return {
*[Symbol.iterator]() {
for(let i = start; i < arr.length && i < end; i++) {
yield arr[i]
}
}
}
}
console.log([...page({arr, pageSize: 5, pageNumber: 2})])
Hey I'm sorry I'm a bit late but we can use the Array.splice(start, end) method except this is much simpler
const page = 2
const step = 2;
const start = page * step - step;
const end = start + step;
const array = [1,2,3,4,5,6]
console.log(array.splice(start, end))
Here is another variation using Array.from with Array.slice
const paginate = (array, n) => {
const pageSize = Math.ceil(array.length / n);
return Array.from({ length: pageSize }, (_, index) => {
const start = index * n;
return array.slice(start, start + n);
});
};
function paginate(array, page_size, page_number) {
// human-readable page numbers usually start with 1, so we reduce 1 in the first argument
return array.slice((page_number - 1) * page_size, page_number * page_size);
}
var arr = [1, 2, 3, 4, 5, 6]
const options = {
//page: parseInt(req.query.page) || 1,
page:1,
limit:10
//limit: parseInt(req.query.limit) || 10,
//customLabels: servCustomLabels,
};
let prev_page = 0;
let next_page = 0;
let h_p_p = null;
let h_n_p = null;
let page_count = Math.ceil((arr.length / options.limit));
if (options.page >= page_count ){ // 2 3
next_page = 0;
}
if(options.page >= 1 && options.page < page_count ){
next_page = options.page + 1;
h_n_p = true;
}else{
next_page = 0;
h_n_p = false;
}
if(options.page <= 1 ){
prev_page =0;
h_p_p = false;
}else{
prev_page = options.page -1 ;
h_p_p = true;
}
console.log(paginate(arr, 2, 2));
console.log({paginator: {
totalDocs: arr.length,
perPage: options.limit,
pageCount: page_count,
currentPage: options.page,
//slNo: 2,
hasPrevPage: h_p_p,
hasNextPage: h_n_p,
prev: prev_page,
next: next_page
}})
function paginate(arr, PerPage) {
let map = {};
let startPage = 1;
arr.forEach((current) => {
if (map[startPage] && map[startPage].length < PerPage) {
map[startPage].push(current);
}
if (!map[startPage]) {
map[startPage] = [current];
}
if (map[startPage] && map[startPage].length >= PerPage) {
startPage++;
}
});
return map;
}
you will find an example on this link
The example below is using iter-ops library (I'm the author).
// our inputs...
const array = [1, 2, 3, 4, 5];
const pageSize = 2;
const pageIndex = 1;
The most efficient way is to process an array as an iterable, so you go through it once.
If you never need other pages, then the fastest way is like this:
import {pipe, skip, page} from 'iter-ops';
const p = pipe(
array,
skip(pageSize * pageIndex), // skip pages we don't want
page(pageSize) // create the next page
).first;
console.log(p); //=> [3, 4]
And if you do need other pages, then you can do:
const p = pipe(
array,
page(pageSize), // get all pages
skip(pageIndex) // skip pages we don't want
).first;
console.log(p); //=> [3, 4]
And in case you need to do further processing:
const i = pipe(
array,
page(pageSize), // get all pages
skip(pageIndex), // skip pages we don't want
take(1), // take just one page
// and so on, you can process it further
);
console.log([...i]); //=> [[3, 4]]
A simple solution using filter:
function paginate(array, pageIndex, pageSize) {
const first = pageIndex * pageSize
const last = (pageIndex * pageSize) + pageSize
return array.filter((_, index) => {
return first <= index && index < last
})
}
for (let pageNum = 1; pageNum <= totalPagesCount; pageNum++){
....
const chunk = articles.slice(
(pageNum - 1) * pageSizeNumbered,
pageNum * pageSizeNumbered,
);
.....
}
I'd go with something like this;
const paginateArray = (array, pageNumber, pageSize) => {
const page = array.slice((pageNumber - 1) * pageSize, pageNumber * pageSize);
return page;
};
const array = [1, 2, 3, 4, 5];
const pageSize = 2;
const pageNumber = 2;
console.log(paginateArray(array, pageNumber, pageSize));
I have an array
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
I want to group it into a set of n arrays such that first n elements in result[0] next n elements in result[1] and if any element is remaining it is discarded.
let sampleOutput = [[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13]] for n = 7;
Here is my code:
function group5(arr, len) {
let result = [];
let loop=parseInt(arr.length/len)
for (let i=0; i<arr.length; i+=len) {
let x = []; let limitReached = false;
for (let j=0; j<len; j++) {
if (arr[i+j]) {
x.push(arr[i+j]);
} else {
limitReached = true;
break;
}
}
if (!limitReached) {
result.push(x);
} else {
break;
}
}
return result;
}
But I am unable to get expected result. I have tried following things.
Map function
Running i loop to arr.len
Checking arr.len % 7
Creating an array for every third element.
This question is not duplicate of Split array into chunks because I have to discard extra elements that can not be grouped into sets of n.
I have to keep the original array Immutable because I am using this on props in a child component. I need a function that does not modify the original array.
It's pretty straigthforward using Array.from
const list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];
function chunkMaxLength(arr, chunkSize, maxLength) {
return Array.from({length: maxLength}, () => arr.splice(0,chunkSize));
}
console.log(chunkMaxLength(list, 7, 2));
What about :
function group5(arr, len) {
let chunks = [];
let copy = arr.splice(); // Use a copy to not modifiy the original array
while(copy.length > len) {
chunks.push(copy.splice(0, len));
}
return chunks;
}
You could use a combination of reduce and filter to achieve the expected result. This example gives you a third control over length which makes the code a bit more reuseable.
let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
const groupNumber = 7;
const groupCount = 2;
const groupArray = (group, size, length) => group.reduce((accumulator, current, index, original) =>
((index % size) == 0)
? accumulator.concat([original.slice(index, index + size)])
: accumulator, []
).filter((single, index) => index < length)
const test = groupArray(arr, groupNumber, groupCount);
console.log(test);
Step by Step
const groupArray = (group, size, length) => {
// if (index modulus size) equals 0 then concat a group of
// length 'size' as a new entry to the accumulator array and
// return it, else return the accumulator
const reducerFunc = (accumulator, current, index, original) =>
((index % size) == 0)
? accumulator.concat([original.slice(index, index + size)])
: accumulator
// if the current index is greater than the supplied length filter it out
const filterFunc = (single, index) => index < length;
// reduce and filter original group
const result = group.reduce(reducerFunc, []).filter(filterFunc)
return result;
}
Also (apart from the existing approaches) you can have a recursive approach like this
function chunks(a, size, r = [], i = 0) {
let e = i + size;
return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}
function chunks(a, size, r = [], i = 0) {
let e = i + size;
return e <= a.length ? chunks(a, size, [...r, a.slice(i, e)], e) : r;
}
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
console.log('Chunk with 3: ', chunks(arr, 3));
console.log('Chunk with 4: ', chunks(arr, 4));
console.log('Chunk with 5: ', chunks(arr, 5));
console.log('Chunk with 6: ', chunks(arr, 6));
console.log('Chunk with 7: ', chunks(arr, 7));
I able to solve the problem with this code
function groupN(n, arr) {
const res = [];
let limit = 0;
while (limit+n <= arr.length) {
res.push(arr.slice(limit, n + limit));
limit += n
}
return res
}
I usually prefer declarative solutions (map, reduce, etc), but in this case I think a for is more understandable:
function groupArray(array, num) {
const group = [];
for (let i = 0; i < array.length; i += num) {
group.push(array.slice(i, i + num));
}
return group;
}
I have a array of 2N elements. For example,[1,2,3,4,5,6,7,8].
Now I want to separate it into an array of random pairs (no repeats).
The result may be:
[[1,3],[2,5],[4,8],[6,7]]
I try to code but I think it is not good. Any better ideas?
function arrSlice(arr) {
if (arr.length % 2 !== 0) return 0;
var
newArr = [],
//temp array.
tmpArr = [];
for (let i = 0; i < arr.length; i++) {
if (!tmpArr.includes(arr[i])) {
var rndIndex;
do {
rndIndex = Math.floor(Math.random() * (arr.length - (i + 1))) + (i + 1);
} while (tmpArr.includes(arr[rndIndex]));
newArr.push([arr[i], arr[rndIndex]]);
tmpArr.push(arr[i]);
tmpArr.push(arr[rndIndex]);
}
}
return newArr;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(arrSlice(arr));
You could create two functions, one to return new shuffled array and other one to slice it.
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
function shuffle(arr) {
return arr.reduce((r, e, i) => {
r.splice(Math.random() * (i + 1), 0, e);
return r;
}, [])
}
function sliceArray(data, n = 2) {
const arr = [];
for (var i = 0; i < data.length; i += n) arr.push(data.slice(i, i + n))
return arr;
}
const result = sliceArray(shuffle(arr), 2);
console.log(JSON.stringify(result))
Here is another approach you could first generate new empty array of sub-arrays and then loop data while there are still elements left and fill empty array.
function create(data, len) {
data = data.slice();
const result = Array.from(Array(Math.ceil(data.length / len)), () => []);
let aN = 0;
while (data.length) {
result[aN].push(data.splice(parseInt(Math.random() * data.length), 1)[0]);
if (result[aN].length == len) aN++;
}
return result;
}
console.log(JSON.stringify(create([1, 2, 3, 4, 5, 6, 7, 8], 2)))
console.log(JSON.stringify(create([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3)))
I would just remove random elements from the array and add them in pairs:
const random = end => Math.floor(Math.random() * end);
function pairedShuffle(array) {
const remove = () => array.splice(random(array.length), 1)[0];
const result = [];
while(array.length >= 2)
result.push([remove(), remove()]);
return result;
}
Alternatively this is a good usecase for generators:
function* pairs(iterable) {
let prev = null;
let i = 0;
for(const el of iterable) {
if(i++ % 2) yield [prev, el];
prev = el;
}
}
function* shuffle(iterable) {
const arr = [...iterable];
while(arr.length)
arr.splice(random(arr.length), 1)[0];
}
Usable as:
const result = [...pairs(shuffle([1,2,3,4]))];
Something like this should work. Majority of this is copied from the Fisher-Yates shuffle here
function arrSlice(array) {
var currentIndex = array.length, randomIndex, temporaryValue;
var newArray = [], tempArray = [];
while (currentIndex !== 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
tempArray.push(array[currentIndex]);
if (tempArray.length == 2) {
newArray.push(tempArray);
tempArray = [];
}
}
return newArray;
}
console.log(arrSlice([1, 2, 3, 4, 5, 6]));
Using random sort and reduce chain
var data = [1, 2, 3, 4, 5, 6, 7, 8];
var res = data.slice()
.sort(_ => Math.random() - 0.5)
.reduce((a, c, i, arr) => (i % 2 ? a : a.concat([arr.slice(i, i + 2)])), [])
console.log(JSON.stringify(res))
function arrSlice (arr) {
return arr
.sort(() => Math.random() > .5) //shuffle
.map((element,index) => index % 2 ? false : [arr[index], arr[index+1]])
.filter(Boolean);
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(arrSlice(arr));
I want to split an array into pairs of arrays.
var arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]
would be
var newarr = [
[2, 3],
[4, 5],
[6, 4],
[3, 5],
[5]
]
You can use js reduce
initialArray.reduce(function(result, value, index, array) {
if (index % 2 === 0)
result.push(array.slice(index, index + 2));
return result;
}, []);
Lodash has a method for this: https://lodash.com/docs/4.17.10#chunk
_.chunk([2,3,4,5,6,4,3,5,5], 2);
// => [[2,3],[4,5],[6,4],[3,5],[5]]
There's no pre-baked function to do that, but here's a simple solution:
var splitPairs = function(arr) {
var pairs = [];
for (var i=0 ; i<arr.length ; i+=2) {
if (arr[i+1] !== undefined) {
pairs.push ([arr[i], arr[i+1]]);
} else {
pairs.push ([arr[i]]);
}
}
return pairs;
};
Yet another that's a bit of a mish-mash of the already-posted answers. Adding it because having read the answers I still felt things could be a little easier to read:
var groups = [];
for(var i = 0; i < arr.length; i += 2)
{
groups.push(arr.slice(i, i + 2));
}
There is now the flexible Array#flatMap(value, index, array):
const pairs = arr.flatMap((_, i, a) => i % 2 ? [] : [a.slice(i, i + 2)]);
And the possibly more efficient, but goofy looking Array.from(source, mapfn?):
const pairs = Array.from({ length: arr.length / 2 }, (_, i) => arr.slice(i * 2, i * 2 + 2))
It's possible to group an array into pairs/chunks in one line without libraries:
function chunks(arr, size = 2) {
return arr.map((x, i) => i % size == 0 && arr.slice(i, i + size)).filter(x => x)
}
console.log(chunks([1, 2, 3, 4, 5, 6, 7])) // -> [[1, 2], [3, 4], [5, 6], [7]]
Here's a good generic solution:
function splitInto(array, size, inplace) {
var output, i, group;
if (inplace) {
output = array;
for (i = 0; i < array.length; i++) {
group = array.splice(i, size);
output.splice(i, 0, group);
}
} else {
output = [];
for (i = 0; i < array.length; i += size) {
output.push(array.slice(i, size + i));
}
}
return output;
}
For your case, you can call it like this:
var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
The inplace argument determines whether the operation is done in-place or not.
Here's a demo below:
function splitInto(array, size, inplace) {
var output, i, group;
if (inplace) {
output = array;
for (i = 0; i < array.length; i++) {
group = array.splice(i, size);
output.splice(i, 0, group);
}
} else {
output = [];
for (i = 0; i < array.length; i += size) {
output.push(array.slice(i, size + i));
}
}
return output;
}
var arr= [2,3,4,5,6,4,3,5,5];
var newarr = splitInto(arr, 2);
disp(newarr);
// or we can do it in-place...
splitInto(arr, 3, true);
disp(arr);
function disp(array) {
var json = JSON.stringify(array);
var text = document.createTextNode(json);
var pre = document.createElement('pre');
pre.appendChild(text);
document.body.appendChild(pre);
}
A slightly different approach than using a for loop for comparison. To avoid modifying the original array slice makes a shallow copy since JS passes objects by reference.
function pairArray(a) {
var temp = a.slice();
var arr = [];
while (temp.length) {
arr.push(temp.splice(0,2));
}
return arr;
}
var array = [2,3,4,5,6,4,3,5,5];
var newArr = pairArray(array);
function pairArray(a) {
var temp = a.slice();
var arr = [];
while (temp.length) {
arr.push(temp.splice(0,2));
}
return arr;
}
document.write('<pre>' + JSON.stringify(newArr) + '</pre>');
I would use lodash for situations like this.
Here is a solution using _.reduce:
var newArr = _(arr).reduce(function(result, value, index) {
if (index % 2 === 0)
result.push(arr.slice(index, index + 2));
return result;
}, []);
var arr = [2,3,4,5,6,4,3,5,5];
var newArr = _(arr).reduce(function(result, value, index) {
if (index % 2 === 0)
result.push(arr.slice(index, index + 2));
return result;
}, []);
document.write(JSON.stringify(newArr)); // [[2,3],[4,5],[6,4],[3,5],[5]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
Here's another solution using lodash helpers:
function toPairs(array) {
const evens = array.filter((o, i) => i % 2);
const odds = array.filter((o, i) => !(i % 2));
return _.zipWith(evens, odds, (e, o) => e ? [o, e] : [o]);
}
console.log(toPairs([2,3,4,5,6,4,3,5,5]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
const items = [1, 2, 3, 4, 5];
const createBucket = (bucketItems, bucketSize) => buckets => {
return bucketItems.length === 0 ? buckets : [...buckets, bucketItems.splice(0, bucketSize)];
};
const bucketWithItems = items.reduce(createBucket([...items], 4), []);
Here is a short and more generic solution:
function splitArrayIntoPairs(arr, n) {
var len = arr.length
var pairs = []
for (let i = 0; i < len; i += n) {
var temp = []
for (var j = i; j < (i + n); j++) {
if (arr[j] !== undefined) {
temp.push(arr[j])
}
}
pairs.push(temp)
}
return pairs
}
Where arr is your array and n is no of pairs
This combines some of the answers above but without Object.fromEntires. The output is similar to what you would get with minimist.
const splitParameters = (args) => {
const split = (arg) => (arg.includes("=") ? arg.split("=") : [arg]);
return args.reduce((params, arg) => [...params, ...split(arg)], []);
};
const createPairs = (args) =>
Array.from({ length: args.length / 2 }, (_, i) =>
args.slice(i * 2, i * 2 + 2)
);
const createParameters = (pairs) =>
pairs.reduce(
(flags, value) => ({
...flags,
...{ [value[0].replace("--", "")]: value[1] }
}),
{}
);
const getCliParameters = (args) => {
const pairs = createPairs(splitParameters(args));
const paramaters = createParameters(pairs);
console.log(paramaters);
return paramaters;
};
//const argsFromNodeCli = process.argv.slice(2); // For node
const testArgs = [
"--url",
"https://www.google.com",
"--phrases=hello,hi,bye,ok"
];
const output = getCliParameters(testArgs);
document.body.innerText = JSON.stringify(output);
Here is another concise but still efficient solution using modern JavaScript (arrow function, Array.prototype.at):
splitPairs = arr =>
arr.reduce((pairs, n, i) =>
(i % 2 ? pairs.at(-1).push(n)
: pairs.push([n]),
pairs), []);
It is (memory-)efficient because it just creates one array for the result and one array for each pair and then modifies them. The case where there is an odd number of elements is handled naturally.
When minified, it is also really concise code:
splitPairs = a=>a.reduce((p,n,i)=>(i%2?p.at(-1)[1]=n:p.push([n]),p),[]);
Using ES6 features:
const arr = [2, 3, 4, 5, 6, 4, 3, 5, 5]
const result = arr.slice(arr.length/2).map((_,i)=>arr.slice(i*=2,i+2))
console.log(result)
Here is another generic solution that uses a generator function.
/**
* Returns a `Generator` of all unique pairs of elements from the given `iterable`.
* #param iterable The collection of which to find all unique element pairs.
*/
function* pairs(iterable) {
const seenItems = new Set();
for (const currentItem of iterable) {
if (!seenItems.has(currentItem)) {
for (const seenItem of seenItems) {
yield [seenItem, currentItem];
}
seenItems.add(currentItem);
}
}
}
const numbers = [1, 2, 3, 2];
const pairsOfNumbers = pairs(numbers);
console.log(Array.from(pairsOfNumbers));
// [[1,2],[1,3],[2,3]]
What I like about this approach is that it will not consume the next item from the input until it actually needs it. This is especially handy if you feed it a generator as input, since it will respect its lazy execution.