Working with your code
Refactor
First of all, let's extract clear & separate function
function getPaged(items, itemsPerPage) {
let pagesContainer = [];
let page = [];
let i = 0;
for (const content of items) {
if (i < itemsPerPage) {
page.push(content);
i++;
} else {
pagesContainer.push(page)
page = [];
page.push(content)
i = 0;
}
if (items.indexOf(content) === items.length - 1) {
pagesContainer.push(page);
}
}
return pagesContainer;
}
console.log(getPaged(props.content, itemsPerPage));
Now, you can notice that the variable i
always equals to page.length
. So we don't need it.
Just replace usage i
with page.length
:
function getPaged(items, itemsPerPage) {
let pagesContainer = [];
let page = [];
for (const content of items) {
if (page.length < itemsPerPage) {
page.push(content);
} else {
pagesContainer.push(page)
page = [];
page.push(content);
}
if (items.indexOf(content) === items.length - 1) {
pagesContainer.push(page);
}
}
return pagesContainer;
}
console.log(getPaged(props.content, itemsPerPage));
Condition if (items.indexOf(content) === items.length - 1)
is not lovely.
We don't really need to add last page inside of cycle. Let's add that page outside:
function getPaged(items, itemsPerPage) {
let pagesContainer = [];
let page = [];
for (const content of items) {
if (page.length < itemsPerPage) {
page.push(content);
} else {
pagesContainer.push(page)
page = [];
page.push(content);
}
}
if (page.length > 0) {
pagesContainer.push(page);
}
return pagesContainer;
}
console.log(getPaged(props.content, itemsPerPage));
There is no reason to create a page & push a new item into it. Because we can create a page with the new item inside.
function getPaged(items, itemsPerPage) {
let pagesContainer = [];
let page = [];
for (const content of items) {
if (page.length < itemsPerPage) {
page.push(content);
} else {
pagesContainer.push(page)
page = [content];
}
}
if (page.length > 0) {
pagesContainer.push(page);
}
return pagesContainer;
}
console.log(getPaged(props.content, itemsPerPage));
Beautify
Let's make some renames in order to make our life shorter:
- itemsPerPage → pageSize
- pagesContainer → pages
- content → item
Also, we should note that the variable pages
(previously pagesContainer
) is not modified. So we can use const
.
function getPaged(items, pageSize) {
const pages = [];
let page = [];
for (const item of items) {
if (page.length < pageSize) {
page.push(item);
} else {
pages.push(page)
page = [item];
}
}
if (page.length > 0) {
pages.push(page);
}
return pages;
}
console.log(getPaged(props.content, itemsPerPage));
Possible enhancement
We can build lazy solution via generators.
function* getPaged(items, pageSize) {
let page = [];
for (const item of items) {
if (page.length < pageSize) {
page.push(item);
} else {
yield page;
page = [item];
}
}
if (page.length > 0) {
yield page;
}
}
console.log(Array.from(getPaged(props.content, itemsPerPage)));
This is cool only in case if you need to post-process your pages in lazy way.
Alternate solution 1
Our alternate solution will be based on a functional top-down approach.
Firstly we will generate all pages from 0
to pageCount
;
And then we will fill each page with its actual content.
const range = (size) => [...Array(size).keys()];
function getPaged(items, pageSize) {
const pageCount = Math.ceil(items.length / pageSize);
const getPage = (pageNo) => range(pageSize)
.map(noInPage => items[pageNo * pageSize + noInPage])
.filter(item => item !== undefined);
return range(pageCount)
.map(pageNo => getPage(pageNo));
}
console.log(getPaged(props.content, itemsPerPage));
Please, note that this solution will be slower. This is because map
and filter
are slow. But this can be solved with transducers
Alternate solution 2
Use lodash/chunk and don't write your own function
Alternate solution 3
Using lodash/groupBy, group items by page. Then return only values of the resulting dictionary.
const getPaged = (items, pageSize) =>
Object.values(_.groupBy(
items,
(item, index) => Math.floor(index / pageSize)
));
console.log(getPaged(props.content, itemsPerPage));