Concentrated Python cuteness

20.03.2014 19:45

Yesterday, I wrote the following piece of Python code to answer a question asked on IRC by Jure. It was more of a joke than a serious suggestion.

Update: In case you want to use this code in some serious application, please be warned that it does not work for a general case. See comments below for some better suggestions on how to solve this task.

def list_pages(page_num, cur_page, n):
	k = sorted([	0, 2*n+1, 
			cur_page-(n+1), cur_page+n, 
			page_num-(2*n+1), page_num])
	return range(1, page_num+1)[k[1]:k[-2]]

What it does is take a list of page numbers from a total of page_num pages. If possible, the list is centered on cur_page and includes n pages in front and back. At the edges, it still returns the list of the same length. For example:

list_pages(10, 1, 2)  = [1, 2, 3, 4, 5]
list_pages(10, 2, 2)  = [1, 2, 3, 4, 5]
list_pages(10, 3, 2)  = [1, 2, 3, 4, 5]
list_pages(10, 4, 2)  = [2, 3, 4, 5, 6]
list_pages(10, 5, 2)  = [3, 4, 5, 6, 7]
list_pages(10, 6, 2)  = [4, 5, 6, 7, 8]
list_pages(10, 7, 2)  = [5, 6, 7, 8, 9]
list_pages(10, 8, 2)  = [6, 7, 8, 9, 10]
list_pages(10, 9, 2)  = [6, 7, 8, 9, 10]
list_pages(10, 10, 2) = [6, 7, 8, 9, 10]

This is likely one of the most incomprehensible pieces of Python code I have ever written. The idea came from Python's cutest clamp function. It's a kind of cleverness I never want to see in a serious product.

The version Jure ended up using took around 30 lines of code to accomplish the same thing. However even with descriptive variable names it's not immediately obvious to me what it does or how it does it. If I would come across it without any additional comments, it would probably take some time and a few tests to see what is its purpose.

I failed to come up with a version that would be self-explanatory.

Perhaps comprehensive code documentation is dead these days, but I think this is one example where an English sentence can be much more expressive than code.

Posted by Tomaž | Categories: Code

Comments

I think your code won't work when the range is bigger than 4*n+3, such that the edge ranges no longer overlap. For instance, for list_pages(11,1,2) we get k=[-2, 0, 3, 5, 6, 11], so the result is 1:6 rather than 1:5 as expected (unless I misunderstood the intent). I think you need to clamp the upper and lower bounds separately (sorry if the formatting breaks):

def list_pages3(page_num, cur_page, n):

width = 2*n+1

a = sorted([1,cur_page-n,page_num-width+1])[1]

b = sorted([width,cur_page+n,page_num])[1]

return range(a,b+1)

If you're not familiar with the cute clamp trick, it may be more legible to just use min/max operations:

a = max(1,min(cur_page-n,page_num-width+1))

return range(a,a+width)

Posted by Spencer

Spencer, you are correct. Actually, I first wrote the version with separate clamps. I then tried it with a single sort and it seemed to work fine and looked cleverer. It was late and I didn't stop to think about it.

Only after getting asked to explain why it works I realized that it was just a coincidence that my test case returned the correct result. Hence my warning in the original post.

Posted by Tomaž

@Spencer, thanks

I think there's an edge case where pages = 3, current = 3 and width = 2, where width can be larger than max number of pages. So this fixes it for me:

def get_range(page_num, cur_page, n):
width = 2*n+1
a = max(1, min(cur_page-n,page_num-width+1) )
return range( a, min(a + width, page_num + 1 ) )

Posted by Jure

Add a new comment


(No HTML tags allowed. Separate paragraphs with a blank line.)