Ike
Ike

Reputation: 771

Better way to do result paging in Scala

I do result paging often (given a page number and a page size calculate start, end and total pages) and I ported this little function from Java to help:

def page(page: Int, pageSize: Int, totalItems: Int) = {
    val from = ((page - 1) * pageSize) + 1
    var to = from + pageSize - 1
    if (to > totalItems) to = totalItems
    var totalPages: Int = totalItems / pageSize
    if (totalItems % pageSize > 0) totalPages += 1
    (from, to, totalPages)
}

And on the receiving side:

val (from, to, totalPages) = page(page, pageSize, totalItems)

Although it works, I'm sure there are more readable and functional ways to do the same thing in Scala. What would be a more scala-like approach?

In particular, I'm trying to find a nicer way of saying:

var to = from + pageSize - 1
if (to > totalItems) to = totalItems

In Java I could do something like:

from + pageSize - 1 + (to > totalItems) ? 1 : 0;

Upvotes: 4

Views: 4542

Answers (2)

Rex Kerr
Rex Kerr

Reputation: 167881

The easiest improvement is just to use functions instead of vars (and avoid shadowing the method name with the argument name, so it's clearer whether you are calling a recursive function or not):

def pageCalc(page: Int, pageSize: Int, totalItems: Int) = {
  val from = ((page - 1) * pageSize) + 1
  val to = totalItems min (from + pageSize - 1)
  val totalPages = (totalItems / pageSize) + (if (totalItems % pageSize > 0) 1 else 0)
  (from, to, totalPages)
}

The key changes are just using the min function instead of a separate var, and letting the if statement return 0 or 1 rather than having it update a var.

Upvotes: 2

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297165

Half of the problem is identifying the pattern:

def pageCalc(page: Int, pageSize: Int, totalItems: Int) = {
    val pages = 1 to totalItems by pageSize
    val from = pages(page - 1)
    val to = from + pageSize - 1 min totalItems
    val totalPages = pages.size
    (from, to, totalPages)
}

Though, really, maybe you could just use a Range directly instead?

Upvotes: 8

Related Questions