# Goto the Nth Page

It is common to need to make a page selection interface. It typically looks like this:

prev 1 ... 3 4 [5] 6 7 ... 173 next


Which means there are totally 173 pages, and you are on the 5th page currently.

This challenge requires you take the total number of pages and the current page number as input, and output a string (or an array) to "display" the page selector.

## Input

2 positive integers

• current page number
• count of pages

It is guaranteed that 1 <= current <= total.

## Output

Output a string or an array which represent the ui for page selectors.

• If output as string, a single space (U+0020) should be used between each pages.
• If output as an array, the array should produce same result as the string after convert each item to string and join them with a single space.
• The three dots (...) is not optional for array output.

## Details

• If current == 1, no "prev" will be outputted, otherwise, "prev" comes first.
• If current == total, no "next" will be outputted, otherwise, "next" comes last.
• The first page (1) and the last page (total) should always be outputted.
• The current page, (current - 1) page, (current - 2) page, (current + 1) page, (current + 2) page should be outputted as long as the are in the range of [1..total].
• No other pages numbers should be outputted.
• Pages outputted should be sorted in ascending order.
• Output should not contain duplicate page numbers.
• Current page should be highlighted by wrap it in a pair of [].
• If there is a gap between any neighbors, three dots (...) should be inserted.

## Test Cases

Current Total    Output
1       1        [1]
1       2        [1] 2 next
1       10       [1] 2 3 ... 10 next
3       3        prev 1 2 [3]
3       6        prev 1 2 [3] 4 5 6 next
4       6        prev 1 2 3 [4] 5 6 next
4       7        prev 1 2 3 [4] 5 6 7 next
3       10       prev 1 2 [3] 4 5 ... 10 next
5       10       prev 1 ... 3 4 [5] 6 7 ... 10 next
10      10       prev 1 ... 8 9 [10]
52      173      prev 1 ... 50 51 [52] 53 54 ... 173 next


## Rules

• This is code-golf, the shortest code wins!
• Might be worth adding 4 , 6 as a test case. Similar to the 3, 6 case, but ensures dots are not added to the left side. – Tom Carpenter Nov 7 '17 at 11:53
• Just gonna YOINK some of these for a web project... – Stan Strum Nov 7 '17 at 17:50
• Building on @TomCarpenter 's comment a 4,7 test case would be greatly appreciated - would insure that both of the boundary cases that exclude ellipses may be concurrently met – Taylor Scott Nov 7 '17 at 21:10
• @TaylorScott Both added. – tsh Nov 8 '17 at 2:12
• @StanStrum The next challenge is to write an infinite scroller. – Carl Nov 8 '17 at 5:47

# Retina, 125113109 107 bytes

.+
$* r1\G 1$'
¶

O1+
\b(1+) \1\b
[$1] .* (1+ 1+ $)|(] 1+ 1+) .* 2 ... 1 ^1 prev 1 1 1 next 1+ .&  Try it online! Link includes test cases. Saved 12 bytes thanks to @MartinEnder. Explanation: .+ *  Convert to unary. r1\G 1'  Generate all the page numbers in reverse order. ¶  Delete the newline separating the input. (There's also a space there from the page number generation anyway.) O1+  Sort the pages back into ascending order. This also sorts the current page, which is now duplicated. \b(1+) \1\b [1]  Unduplicate and wrap []s around the current page.  .* (1+ 1+ \[)|(] 1+ 1+) .* 2 ... 1  Add an ellipsis if the current page is at least 5, or if there are at least 4 pages after the current page. (Note trailing space, to avoid including the last page in the ellipsis.) ^1 prev 1  Add the prev if the current page is not 1. 1 1 next  Add the next if the current page is not the last page. 1+ .&  Convert back to decimal. • Saved a few bytes: tio.run/… (one of which required changing the input format to linefeed separation). – Martin Ender Nov 7 '17 at 12:41 • @MartinEnder Thanks, I particularly like that trailing ellipsis golf, although I think I can shave off another <s>three</s> four bytes. – Neil Nov 7 '17 at 16:26 # JavaScript (ES6), 130122 121 bytes Invoke with currying syntax, e.g. f(3)(10). x=>X=>[x>1&&'prev 1',x>4&&'...',x>3&&x-2,x>2&&x-1,[{x}],(X-=x)>1&&x+1,X>2&&x+2,X>3&&'...',X&&X+x+' next'].filter(_=>_)  f= x=>X=>[x>1&&'prev 1',x>4&&'...',x>3&&x-2,x>2&&x-1,[{x}],(X-=x)>1&&x+1,X>2&&x+2,X>3&&'...',X&&X+x+' next'].filter(_=>_) console.log(f(1)(1)) console.log(f(1)(2)) console.log(f(1)(10)) console.log(f(3)(3)) console.log(f(3)(6)) console.log(f(4)(6)) console.log(f(4)(7)) console.log(f(3)(10)) console.log(f(5)(10)) console.log(f(10)(10)) console.log(f(52)(173)) Try it online! -1 byte (Arnauld): Set X to X-x. • Gotta love those lambdas – Stan Strum Nov 7 '17 at 21:08 • You should add +8 ... The .join is not part of your count! I was going crazy trying to figure why your code would work without a join, while my similar code wouldn't. Then I say you just didn't include it in your solution, but did include it in your snippet! – nl-x Nov 8 '17 at 13:30 • @nl-x Whoops! I forgot to update my snippet. The challenge allows you to output a string or an array; I'd recommend you output as an array. – darrylyeo Nov 8 '17 at 17:30 # 6502 machine code (C64), 160 bytes 00 C0 20 9B B7 86 FB CA F0 01 CA 86 FD 20 9B B7 86 FC A6 FB E8 E4 FC B0 01 E8 86 FE A2 01 E4 FB F0 1A A9 91 A0 C0 20 1E AB A2 02 E4 FD B0 0D A9 2E 20 D2 FF CA 10 FA 20 3F AB A6 FD 86 9E E4 FB D0 05 A9 5B 20 D2 FF A9 00 20 CD BD A6 9E E4 FB D0 05 A9 5D 20 D2 FF 20 3F AB A6 9E E4 FC F0 25 E4 FE F0 05 E8 86 9E D0 D5 E8 E4 FC F0 0D A2 02 A9 2E 20 D2 FF CA 10 FA 20 3F AB A6 FC A9 00 20 CD BD 20 3F AB A6 FC E4 FB F0 07 A9 99 A0 C0 20 1E AB 60 50 52 45 56 20 31 20 00 4E 45 58 54 00  Online demo -- Usage: sys49152,[current],[total], e.g. sys49152,5,173. The numbers must be in the range [1..255] with current <= total. As this wasn't specified otherwise, this is the "natural" unsigned integer range on an 8bit processor. Explanation as commented disassembly listing:  00 C0 .WORD C000 ; load address .C:c000 20 9B B7 JSR B79B ; read 8bit integer .C:c003 86 FB STX FB ; store current page .C:c005 CA DEX ; calculate lower start for ... .C:c006 F0 01 BEQ .stl .C:c008 CA DEX .C:c009 .stl: .C:c009 86 FD STX FD ; ... range and store .C:c00b 20 9B B7 JSR B79B ; read 8bit integer .C:c00e 86 FC STX FC ; store total pages .C:c010 A6 FB LDX FB ; load current page .C:c012 E8 INX ; calculate upper end for ... .C:c013 E4 FC CPX FC .C:c015 B0 01 BCS .stu .C:c017 E8 INX .C:c018 .stu: .C:c018 86 FE STX FE ; ... range and store .C:c01a A2 01 LDX #01 ; check whether first page is current .C:c01c E4 FB CPX FB .C:c01e F0 1A BEQ .sequence ; then directly to sequence .C:c020 A9 91 LDA #<.prev ; output string for ... .C:c022 A0 C0 LDY #>.prev .C:c024 20 1E AB JSR AB1E ; ... "prev 1 " .C:c027 A2 02 LDX #02 ; check whether page 2 is in range ... .C:c029 E4 FD CPX FD .C:c02b B0 0D BCS .sequence ; ... then directly to sequence .C:c02d A9 2E LDA #2E ; load character '.' .C:c02f .ellip1: .C:c02f 20 D2 FF JSR FFD2 ; output ... .C:c032 CA DEX .C:c033 10 FA BPL .ellip1 ; ... 3 times .C:c035 20 3F AB JSR AB3F ; output space .C:c038 A6 FD LDX FD ; load lower start for range .C:c03a .sequence: .C:c03a 86 9E STX 9E ; store to temporary .C:c03c .seqloop: .C:c03c E4 FB CPX FB ; compare with current .C:c03e D0 05 BNE .notcurrent1 ; yes -> output '[' .C:c040 A9 5B LDA #5B .C:c042 20 D2 FF JSR FFD2 .C:c045 .notcurrent1: .C:c045 A9 00 LDA #00 .C:c047 20 CD BD JSR BDCD ; output number .C:c04a A6 9E LDX 9E ; compare with current .C:c04c E4 FB CPX FB .C:c04e D0 05 BNE .notcurrent2 ; yes -> output ']' .C:c050 A9 5D LDA #5D .C:c052 20 D2 FF JSR FFD2 .C:c055 .notcurrent2: .C:c055 20 3F AB JSR AB3F ; output space .C:c058 A6 9E LDX 9E .C:c05a E4 FC CPX FC ; compare position with last page .C:c05c F0 25 BEQ .printnext ; if eq jump to part printing "next" .C:c05e E4 FE CPX FE ; compare position to upper end of range .C:c060 F0 05 BEQ .printellip2 ; if eq jump to part printing "..." .C:c062 E8 INX .C:c063 86 9E STX 9E ; next number .C:c065 D0 D5 BNE .seqloop ; and repeat loop for sequence .C:c067 .printellip2: .C:c067 E8 INX .C:c068 E4 FC CPX FC ; compare next number with last page .C:c06a F0 0D BEQ .printlast ; if eq jump to part printing page num .C:c06c A2 02 LDX #02 .C:c06e A9 2E LDA #2E ; load character '.' .C:c070 .ellip2: .C:c070 20 D2 FF JSR FFD2 ; output ... .C:c073 CA DEX .C:c074 10 FA BPL .ellip2 ; ... 3 times .C:c076 20 3F AB JSR AB3F ; output space .C:c079 .printlast: .C:c079 A6 FC LDX FC ; output last page number .C:c07b A9 00 LDA #00 .C:c07d 20 CD BD JSR BDCD .C:c080 20 3F AB JSR AB3F ; output space .C:c083 .printnext: .C:c083 A6 FC LDX FC ; compare current page with last page .C:c085 E4 FB CPX FB .C:c087 F0 07 BEQ .done ; if eq nothing else to do .C:c089 A9 99 LDA #<.next ; output string for ... .C:c08b A0 C0 LDY #>.next .C:c08d 20 1E AB JSR AB1E ; "next" .C:c090 .done: .C:c090 60 RTS .C:c091 .prev: .C:c091 50 52 45 56 .BYTE "prev" .C:c095 20 31 20 00 .BYTE " 1 ", 00 .C:c099 .next: .C:c099 4E 45 58 54 .BYTE "next" .C:c09d 00 .BYTE 00  # R, 214 bytes 168 bytes function(c,m,~=function(x,y)if(x)cat(y)){o=-2:2+c o=o[o>0&o<=m] o[o==c]=paste0('[',c,']') c>1~'prev ' c>3~'1 ' c>4~' ... ' T~o c+3<m~' ...' c+2<m~c('',m) c<m~' next'}  Try it online! Thanks to @user2390246 for some great golfing tips • 197 bytes – user2390246 Nov 7 '17 at 9:36 • 186 bytes with a reversal of logic. Doesn't really feel like a distinct premise. – CriminallyVulgar Nov 7 '17 at 14:05 • 165 bytes with further golfing. Also doesn't use the function c(), which gets rid of the horrible confusion with the object called c. – user2390246 Nov 7 '17 at 15:46 • Back up to 171 bytes correcting an error that appears in several of the commented versions! – user2390246 Nov 7 '17 at 16:15 • Another little improvement for 164 bytes. Sorry for completely hijacking this, I got a bit carried away! – user2390246 Nov 8 '17 at 10:40 # APL (Dyalog), 83 82 bytes Anonymous infix function taking current as left argument and total as right argument. {('prev '/⍨⍺>1),('x+'⎕R'...'⍕∊(⊂1⌽'][',⍕)@⍺⊢'x'@(~∊∘(1,⍵,⍺+3-⍳5))⍳⍵),' next'/⍨⍺<⍵}  Try it online! {} explicit lambda where ⍺ and ⍵ represent the left and right arguments: ⍺<⍵ is current smaller than total? ' next'/⍨ if so (lit. use that to replicate) the text (), prepend the following: ⍳⍵ɩntegers 1 through total 'x'@() replace with an x at the positions where the items are… ~ not ∊ members of 1 one , followed by ⍵ the total , followed by ⍳5 the first five ɩntegers ([1,2,3,4,5]) 3- subtracted from three ([2,1,0,-1,-2]) ⍺+ added to the current ([⍺+2,⍺+1,⍺,⍺-1,⍺-2]) ⊢ yield that (serves to separate ⍺ from 'x') () apply the following tacit function at the current position: ⍕ format (stringify) '][', prepend the text 1⌽ rotate one step leftward (moves the ] to the end) ⊂ enclose (so that it is a scalar which will fit in the single indicated position) ∊ϵnlist (flatten – because we made it nested when we inserted brackets) ⍕ format (stringify – 1 space separating numbers from each other and from x runs) 'x+'⎕R'...' PCRE Replace x runs with three periods (), prepend the following: ⍺>1 is current larger than 1? 'prev '/⍨ if so (lit. use that to replicate) the text # Wolfram Language (Mathematica), 131114 109 bytes Range@#2/.{#->"["<>(t=ToString)@#<>"]",1->"prev 1",#2->t@#2<>" next",#-3|#+3:>"...",x_/;Abs[x-#]>2:>Nothing}&  Try it online! ## How it works Lots of replacing. Starting with a list of all pages, replace, in order: 1. #->"["<>(t=ToString)@#<>"]": the current page with a bracketed string, 2. 1->"prev 1": page 1 with the string prev 1, 3. #2->t@#2<>" next": the last page with the string (number) next, with 4. #-3|#+3:>"...": page current-3 and page current+3 with the string "...", 5. x_/;Abs[x-#]>2:>Nothing: all other (integer) pages below current-2 or above current+2 with nothing. (Yes, Nothing is a built-in.) # Funky, 218 210 bytes Saved some bytes, some of which thanks to tsh p=>m=>{t={}a=t::push b=t::pop fori=p-2i<p+3i++a(i)t[2]="[%i]"%p whilet[0]<1b(0)whilet[n=-1+#t]>m b(n)ifp>4a(0,"...")ifp>3a(0,1)ifp>1a(0,"prev")ifp<m-3a("...")ifp<m-2a(m)ifp<m a("next")t::reduce((a,b)=>a+" "+b)}  Try it online! • I don't know Funky, but it seems that i<=p+2 can be golfed to i<p+3,and t[2]="["+t[2]+"]" may be t[2]="["+p+"]"? – tsh Nov 7 '17 at 7:55 # Python 2, 136 130 bytes lambda p,n:[i for i,j in zip(['prev',1,'...',p-2,p-1,[p],p+1,p+2,'...',n,'next'],[1,3,4,2,1,.1,-n,1-n,3-n,2-n,-n])if p*cmp(j,0)>j]  Try it online! If output as an array, the array should produce same result as the string after convert each item to string and join them with a single space. Try it online! in prettified form, where you can see the footer translates quite literally to "convert each to string, join on spaces". This is an alternative to Lynn's approach. • Save a byte with i or'...' and zeros (like this) – Jonathan Allan Nov 7 '17 at 16:29 # Python 2, 135 bytes lambda c,t:re.sub(' +',' ... ','prev '*(c>1)+' '.join([x,[x]][x==c]*(x%t<2or-3<x-c<3)for x in range(1,t+1))+' next'*(c<t)) import re  Try it online! First we create a string like prev 1 3 4 [5] 6 7 10 next, which has “gaps” caused by erasing some numbers but not their delimiting spaces. Then we replace any run of 2+ spaces by ... using a regex. • You can flip (-3<x-c<3or x%t<2) to (x%t<2or-3<x-c<3) for -1, both arguments to the or operator will return a boolean value. – Erik the Outgolfer Nov 7 '17 at 13:32 # Java 8, 201200 197 bytes t->n->(n<2?"[1] ":"prev 1 ")+(n>4?"... "+(n-2)+" "+~-n+" ["+n+"] ":n>3?"2 3 [4] ":n>2?"2 [3] ":n>1?"[2] ":"")+(n<t?(n>t-2?"":n>t-3?t-1+" ":n>t-4?(t-2)+" "+~-t+" ":++n+" "+-~n+" ... ")+t+" next":"")  Explanation: Try it here. t->n-> // Method with two integer parameters and String return-type (n<2? // If the current page is 1: "[1] " // Start with literal "[1] " : // Else: "prev 1 ") // Start with literal "prev 1" +(n>4? // +If the current page is larger than 4: "... " // Append literal "... " +(n-2)+" " // + the current page minus 2, and a space ~-n // + the current page minus 1, and a space +" ["+n+"] " // + "[current_page]" and a space :n>3? // Else-if the current page is 4: "2 3 [4] " // Append literal "2 3 [4] " :n>2? // Else-if the current page is 3: "2 [3] " // Append literal "2 [3] " :n>1? // Else-if the current page is 2: "[2] " // Append literal "[2] " : // Else (the current page is 1): "") // Append nothing +(n<t? // +If the current page and total amount of pages are not the same: (n>t-2? // If the current page is larger than the total minus 2: "" // Append nothing :n>t-3? // Else-if the current page is larger than the total minus 3: t-1+" " // Append the total minus 1, and a space :n>t-4? // Else-if the current page is larger than the total minus 4: (t-2)+" " // Append the total minus 2, and a space +~-t+" " // + the total minus 1, and a space : // Else: ++n+" " // Append the current page plus 1, and a space +-~n+ // + the current page plus 2, and a space " ... ") // + literal "... " +t // + the total itself +" next") // + literal " next" : // Else (current page and total amount of pages are the same): "") // Append nothing // End of method (implicit / single-line return-statement)  # Java (OpenJDK 8), 218179177167 166 bytes c->t->{String p,e="... ",x="["+c+"] ";int i=c-2;for(p=c>1?"prev 1 "+(c>4?e:""):x;i<c+3;i++)p+=i>1&i<t?i==c?x:i+" ":"";return p+(i<t-1?e:"")+(c<t?t+" next":t>1?x:"");}  Try it online! • Nice answer, shorter than mine! You can golf five bytes by putting a space already after "["+c+"] ";: 172 bytes – Kevin Cruijssen Nov 7 '17 at 15:48 • Oh, and one more byte by putting the last p+= before the for-loop inside the for-loop declaration: 171 bytes – Kevin Cruijssen Nov 7 '17 at 15:50 # Jelly, 59 bytes +2Rṫ-4>Ðḟ⁹1;;QµI’a3R”.ṁ⁸żẎ Ị¬;n“¢©ỵY“¡&ç»ẋ"W€jçLÐfKṣ⁸j⁸WŒṘ¤  A full program* printing the result to STDOUT. Takes arguments current and total in that order. Try it online! or see the test-suite. ### How? +2Rṫ-4>Ðḟ⁹1;;QµI’a3R”.ṁ⁸żẎ - Link 1, numbers and ellipses: current, total - e.g. 52, 173 2 - literal two 2 + - add to current 54 R - range [1,2,3,...,53,54] -4 - literal minus four -4 ṫ - tail from index (i.e. right five) [50,51,52,53,54] ⁹ - chain's right argument, total 173 Ðḟ - filter discard if: > - greater than? [50,51,52,53,54] 1 - literal one 1 ; - concatenate [1,50,51,52,53,54] ; - concatenate (implicit right = total) [1,50,51,52,53,54,173] Q - unique (remove excess 1 and/or total) [1,50,51,52,53,54,173] µ - new monadic chain, call that X I - incremental differences [49,1,1,1,1,119] ’ - decrement (vectorises) [48,0,0,0,0,118] 3 - literal three 3 a - logical and (vectorises) [3,0,0,0,0,3] R - range (vectorises) [[1,2,3],[],[],[],[],[1,2,3]] ”. - literal '.' character '.' ṁ - mould like that [['.','.','.'],[],[],[],[],['.','.','.']] ⁸ - chain's left argument, X [1,50,51,52,53,54,173] ż - zip with that [[1,['.', '.', '.']],[50,[]],[51,[]],[52,[]],[53,[]],[54,['.','.','.']],[173]] Ẏ - tighten [1,['.', '.', '.'],50,[],51,[],52,[],53,[],54,['.','.','.'],173] Ị¬;n“¢©ỵY“¡&ç»ẋ"W€jçLÐfKṣ⁸j⁸WŒṘ¤ - Main link: current, total e.g. 52, 173 Ị - insignificant? (abs(current)<=1) 0 ¬ - logical not 1 n - not equal (current != total) 1 ; - concatenate [1,1] “¢©ỵY“¡&ç» - list of compressed strings [['p','r','e','v'], ['n','e','x','t']] " - zip with: ẋ - repeat (zeros -> empty lists) [['p','r','e','v'], ['n','e','x','t']] W€ - wrap €ach (prep for the join) [[['p','r','e','v']], [['n','e','x','t']]] ç - call last link (1) as a dyad [1,['.', '.', '.'],50,[],51,[],52,[],53,[],54,['.','.','.'],173] j - join [['p','r','e','v'],1,['.','.','.'],50,[],51,[],52,[],53,[],54,['.','.','.'],173,['n','e','x','t']] Ðf - filter keep if: L - length (removes empty lists) [['p','r','e','v'],1,['.','.','.'],50,51,52,53,54,['.','.','.'],173,['n','e','x','t']] K - join with spaces ['p','r','e','v',' ',1,' ','.','.','.',' ',50,' ',51,' ',52,' ',53,' ',54,' ','.','.','.',' ',173,' ','n','e','x','t'] ⁸ - chain's left argument, current 52 ṣ - split at that [['p','r','e','v',' ',1,' ','.','.','.',' ',50,' ',51,' ',],[,' ',53,' ',54,' ','.','.','.',' ',173,' ','n','e','x','t']] ¤ - nilad followed by link(s) as a nilad: ⁸ - chain's left argument, current 52 W - wrap [52] ŒṘ - Python string representation ['[','5','2',']'] j - join ['p','r','e','v',' ',1,' ','.','.','.',' ',50,' ',51,' ','[','5','2',']',' ',53,' ',54,' ','.','.','.',' ',173,' ','n','e','x','t'] - implicit print prev 1 ... 50 51 [52] 53 54 ... 173 next  * As a dyadic link taking current on the left and total on the right this returns a list with a mix of characters and integers; this list includes the spaces. The byte K cannot simply be removed to adhere to the spec however, since the result would then have the bracketed current as separate characters (like [...'[','5','2',']'...]) so the "convert each item to string and join them with a single space" would fail to produce the desired result) # Python 2, 178 170 bytes x,y=input() e="... ","" o=("Prev 1 ","[1] ")[y<2]+e[y<5] for z in range(2,x):o+=("",(z,[z])[z==y]+" ")[y-3<z<y+3] print o+("",e[x-y<4]+(x+" Next",[x])[y==x])[x>1]  Try it online! Second attempt after reading the rules more carefully. -8 by losing some unneeded brackets. # Octave, 169 196 190 181 175 169 166 bytes @(n,m)(r=[(n>1)*'prev ' (g=n>4)*'1 ... ' (s=@sprintf)(f='%d ',max(n-3+g,1):n-1) s('[%d]',n) 32*(q=n<m) s(f,n+1:min(n+3-(l=n<m-3),m)) l*['... ' s(f,m)] q*'next'])(r>0)  Try it online! I'll add an explanation later on. Hmm, seems there were some issues with the output format. These have now been resolved - all outputs are correct. But alas it cost 27 bytes. Managed to claw all of those back though with a bit of fat trimming. • Save 6 bytes by using * instead of .* - thanks @StewieGriffin • Save 9 bytes using sprintf instead of num2str as I already had that handle in s. • Save 6 bytes by pulling [] into the sprint call. • Save 6 bytes by finding a way to reduce the number of comparisons. • Save 3 bytes by removing need for strtrim() without causing trailing space. • There is 1 more space after number 54 in your output. – tsh Nov 7 '17 at 9:58 • @tsh fixed now. I've added all test cases to the TIO output. – Tom Carpenter Nov 7 '17 at 11:55 # C# (.NET Core), 195 192 bytes Saved 3 bytes thanks to Kevin Cruijssen. c=>t=>{var n=c>1?"prev ":"";n+=c>4?"1 ... ":c<2?"[1] ":"1 ";if(t>1){for(int i=c-3;i++<c+2;)if(i>1&i<t)n+=i==c?"[{i}] ":i+" ";n+=c<t-4?"... "+t:c==t?"[{t}]":t+"";n+=c<t?" next":"";}return n;}  Try it online! • You can save 2 bytes by removing the brackets of the for-loop. And 1 more by using a currying input c=>t=>. Try it here: 192 bytes – Kevin Cruijssen Nov 7 '17 at 16:28 C++ - 247 bytes #include <iostream> #define c std::cout<< #define N (a-i<3?i-a<2?1:b-i:a-i-2) void s(int a,int b){if(a>1)c"prev ";for(int i=1;i<=b&&N!=0;i+=N)c(i==1?"":" ")<<(a==i?"[":"")<<i<<(a==i?"]":"")<<(N>1?" ...":"");if(a<b-2)c" "<<b;if(a<b)c" next";c"\n";}  Try it online! • Note that "No other pages numbers should be outputted." – tsh Nov 7 '17 at 11:19 • Ohh sorry I missed that rule. I'll correct it soon. – BalazsToth Nov 7 '17 at 11:35 • Also, the link is broken. – Ian H. Nov 7 '17 at 14:42 • @Appleguy: look at this -- your code to be measured goes in the "code" field on TIO. Then you can easily create your whole post from there. – Felix Palmen Nov 8 '17 at 6:13 # Python 2, 128 124 bytes -4 bytes thanks to Jonathan Allan! lambda c,l:["prev"]*(c>1)+[range(1,c),[1,"...",c-2,c-1]][c>4]+[[c]]+[range(c+1,l+1),[c+1,c+2,"...",l]][l-c>4]+["next"]*(c<l)  Try it online! Output as a list, but tio link includes pretty-print. • while ~0: is an odd thing to use when while 1: works fine. – Jonathan Allan Nov 7 '17 at 18:43 • @JonathanAllan I know :P - But it still works :D – Mr. Xcoder Nov 7 '17 at 18:44 • -4 bytes moving the [[c]] out (like this) EDIT - so does while 2*3*4*5*6*7*8*9*'I know a song that will get on your nerves, get on your nerves, get on your nerves;\n': :p – Jonathan Allan Nov 7 '17 at 18:48 • @JonathanAllan Yes thanks, I was just playing around with it because I felt it's redundant. – Mr. Xcoder Nov 7 '17 at 18:49 # PHP, 157 150 bytes taking the details literally turned out to be the shortest approach: [,k,n]=argv;for(k>1&&print"prev ";i++<n;)g=in_array(i,range(k-2,k+2)+[5=>1,n])?!printi-k?"i ":"[i] ":g||print"... ";k<n&&print next;  Run with php -nr '<code>' <curpage> <numpages> or try it online. # CJam, 74 q~\:A\:B]3e*[1T4A3+1A].>["prev"1'.3*_B"next"]:a.*3/5,A2-f+B,2>&*:+_A#Aatp  Outputs as array. Try it online Replace the final p with S* to output as string. Explanation: q~ read and evaluate the input (pushing 2 numbers on the stack) \:A\:B store the numbers in A and B, keeping them in the same order ]3e* wrap in array, then repeat each number 3 times - [A A A B B B] [1T4 make an array containing 1, 0 (T=0 by default), 4, A3+1A] then A+3, 1, and A .> compare the 2 arrays element by element - [A>1 A>0 A>4 B>A+3 B>1 B>A] (each result is 1 or 0) ["prev"1 make an array containing "prev", 1, '.3*_ "..." twice ("..." = '.' repeated 3 times), B"next"] then B and "next" :a wrap each of its elements in an array - [["prev"][1]["..."]…] .* repeat each of these arrays according to the previous array e.g. ["prev"] is repeated A>1 times - ["prev"] if A>1, else [] [1] is repeated A>0 times (always 1), etc. obtaining an array of 6 arrays, some of which may be empty 3/ split into 2 arrays of 3 arrays each (between the "..." parts) 5,A2-f+ make an array [0 1 2 3 4] then add A-2 to each element B,2>& intersect with the array [2 3 … B-1] (these are the middle numbers) * join the 2 previous arrays by adding these numbers between them :+ concatenate all these arrays and numbers together obtaining an array containing only numbers and strings _A# duplicate the array then find the position of A in it Aa generate the "[A]" string (with the actual number for A) by wrapping A in an array and getting its string representation t put it in the array at A's position p print the array's string representation  ## Haskell, 145 129 bytes s x=show x a#t=["prev 1"|a>1]++["..."|a>4]++map s[max 4a-2..a-1]++s[a]:map s[a+1..min(a+3)t-1]++["..."|t-a>3]++[s t++" next"|a<t]  Try it online! Edit: @Ørjan Johansen saved 16 bytes. Thanks! • (1) You can drop the unwords, array output is permitted. (2) s x=show x; ... s[a] is shorter, after which it can be merged with the next one with : and map, and then id=<< becomes longer than just using ++s. (3) max 4a-2 and min(a+3)t-1 are shorter. Try it online! – Ørjan Johansen Nov 24 '17 at 1:33 ## Golf Script - 104 characters ~\:a;:b;1a<'prev '*3a<'1 ... '*[5,{a 2-+}/]{.0>\b)<&},{.a={'['\']'}*' '}/;b a-:c 2>' ... 'b+*0c<' next'*  ### Ungolfed ~\:a;:b; # a = 1st arg, b = 2nd arg 1a<'prev '* # if a > 1: print 'prev ' 3a<'1 ... '* # if a > 3: print '1 ... ' [5,{a 2-+}/] # creates an array [a-2 a-1 a a+1 a+2] {.0>\b)<&}, # keeps only elements >0 and <=b { .a={'['\']'}* # puts '[' ']' around the element equal to a ' '}/; # prints each element with a leading space b a-:c 2>' ... 'b+* # if b-a > 2: print ' ... ' + b 0c<' next'* # if b-a > 0: print ' next'  # Perl 5, 113+1 (-p) 109 +3(-pal) bytes _=join",1..<>;s/\b@F\b/[&]/;s/^1/prev 1/;s/\d/& next/;s/(^|$ )\w+ \w+ \K[\w ]*(?= \w+ \w+( \[|$))/.../g


Try it online

• Nice use of  $  and $'! Had a little play with this, but wasn't able to get it down much, but by using <> instead of the regex and using -a to keep a reference to $_, I was able to drop to 111: Try it online! (-l added for readability) – Dom Hastings Nov 7 '17 at 16:39 • Fine, I didn't think to @F – Nahuel Fouilleul Nov 7 '17 at 16:51 • I've been enjoying the use of "@F" for singular inputs, it's a nice workaround! The -l isn't needed in byte count though, only for running all tests at once :). I didn't say, but your ellipsis validation is very nice! – Dom Hastings Nov 7 '17 at 16:55 • indeed i've just seen one of my first posts could be improved – Nahuel Fouilleul Nov 7 '17 at 17:10 # Ruby, 127 bytes I'm not particularly happy with this, especially the prev/next logic. ->c,t{"prev #{(1..t).chunk{|n|n<2||n==t||n>c-3&&n<c+3}.map{|t,a|t ?a:?.*3}*" "} next".sub(/(prev )?\b(#{c})\b( next)?/,'[\2]')}  Try it online! ## Ungolfed ->c,t{ "prev #{ (1..t) .chunk {|n| n < 2 || n == t || n > c - 3 && n < c + 3 } .map {|t,a| t ? a : ?. * 3 } * " " } next" .sub(/(prev )?\b(#{ c })\b( next)?/, '[\2]') }  # PHP (Browser), 267 Bytes <?php parse_str($_SERVER['QUERY_STRING']);$c=$a!=1?$a>3?$a>4?'prev 1 . . . ':'prev 1 ':'prev ':'[1] ';$d=$a<$b-2?$a+3:$b;for($i=$a<=2?$a==1?$i=2:$i=$a-1:$i=$a-2;$i<$d;$i++)$c.=$a==$i?"[$i] ":"$i ";if($a<$b-2)$c.=" . . . $b next";else$c.=$a==$b?"[$b]":"$b next";echo $c?>  Try it online! Definitely not as small as it could have been, and as was demonstrated above, using PHP in command line can be much smaller. The input is through GET requests, a is the selected number, b is the limit. This looks like foo.bar.com/index.php?a=2&b=12 # Ungolfed <? parse_str($_SERVER['QUERY_STRING']);
$c=$a!=1?$a>3?$a>4?'prev 1 . . . ':'prev 1 ':'prev ':'[1] ';
$d=$a<$b-2?$a+3:$b; for($i=$a<=2?$a==1?$i=2:$i=$a-1:$i=$a-2;$i<$d;$i++)
$c.=$a==$i?"[$i] ":"$i "; if($a<$b-2)$c.=" . . . $b next";else$c.=$a==$b?"[$b]":"$b next";
echo $c ?>  I am pretty sure my ternary operators can be improved, feel free to try. • Making my answer work in a browser would cost one or two bytes: [,$k,$n]=$argv; --> <?[$k,$n]=$_GET; if I insist on current page being the first argument and number of pages the second; <?extract($_GET); if I want to use named arguments. – Titus Nov 8 '17 at 11:33
• fails for a=b-3; replace $a<$b-2 with $a<$b-3 to fix. – Titus Nov 8 '17 at 13:45
• golfed: <?=($a=$_GET['a'])>1?'prev 1 ':'[1] ',$a>4?'... ':'';for($i=$a>4?$a-3:1;$i<$a+3&++$i<$b=$_GET['b'];)echo$a-$i?"$i ":"[$i] ";echo$a<$b-3?"... ":"",$a<$b?"$b next":"[$b]"; (169 bytes) – Titus Nov 8 '17 at 14:28 # IBM/Lotus Notes Formula, 217 211 Bytes -2 with thanks to @KevinCruijssen -4 by using variables for the @Text values o:=@If(a=1;"[1]";"Prev 1 ")+@If(a>4;"... ";"");@For(x:=2;x<b;x:=x+1;T:=@Text(x);o:=o+@If(x>a-3&x<a+3;@If(a=x;"["+T+"]";T)+" ";""));Z:=@Text(b);o:=o+@If(b>1;@If(b-a>3;"... ";"")+@If(a=b;"["+Z+"]";Z+" Next");"");o  Basically a port of my Python 2 answer just for the fun of trying to remember how to use Formula. There's no TIO for Formula so here's a screenshot of some of the test cases: • Is there a reason why spaces are required at x>a-3 & x<a+3 in Lotus Notes Formula? Is &x reserved for something, or is there no reason in particular why the spaces on both sides are mandatory? I never programmed in this language btw, was just curious. :) – Kevin Cruijssen Nov 7 '17 at 16:23 • @KevinCruijssen - To be honest I don't know. Never thought of trying it without. Too used to writing readable code :-). I'll check tomorrow when I get to a machine with Notes installed and let you know. – ElPedro Nov 7 '17 at 18:11 • @KevinCruijssen - you were right! – ElPedro Nov 8 '17 at 8:51 • Hehe, glad I could help. :) +1 from me, and I see you've golfed some more by creating a variable for @Text. When I saw it was used two times two yesterday it crossed my mind that might be possible. – Kevin Cruijssen Nov 8 '17 at 9:03 # Excel VBA, 202 201 Bytes Anonymous VBE immediate window function that takes input from range A1:A2 and outputs to the VBE immediate window. For i=[Max(A1-2,1)]To[Min(A1+2,A2)]:s=s &IIf([A1]=i,"[" &i &"]",i)&" ":Next:?[If(A1=1,"","prev "&If(A1>3,1&If(A1>4," ... "," "),""))]s[If(A1<A2,If(A1-A2<-3,"... ","")&If(A1-A2<-2,A2&" ","")&"next","")]  ### Subroutine Version Included for readablity Public Sub PageSelect(Optional ByVal Current As Long = -1, _ Optional ByVal Total As Long = -1) Call Sheet1.Activate Let [A1] = IIf(Current = -1, [A1], Current) Let [A2] = IIf(Total = -1, [A1], Total) Dim s As String Let s = "" For i = [Max(A1-2,1)] To [Min(A1+2,A2)] Step 1 Let s = s & IIf([A1] = i, "[" & i & "]", i) & " " Next Debug.Print [If(A1=1,"","prev "&If(A1>3,1&If(A1>4," ... "," "),""))]; _ s; _ [If(A1<A2,If(A1-A2<-3,"... ","")&If(A1-A2<-2,A2&" ","")&"next","")] End Sub  # PowerShell, 237 bytes param($a,$n)('prev 1','[1]')[$n-lt2]+" ... $($n-2) $($n-1) [$n]"*($n-gt4)+" 2 3 [4]"*($n-eq4)+" 2 [3]"*($n-eq3)+" [2]"*($n-eq2)+"$($n+1)$($n+2) ..."*($n-lt$a-3)+"$($n+1)$($n+2)"*($n-eq$a-3)+"$($n+1)"*($n-eq$a-2)+"$a next"*($n-ne$a)


Try it online!

One gigantic string concatenation with way too many dollar signs. Working on golfing further. Nope, I think this is as short as this approach can go.

# Javascript (ES6), 265263258240239220194193182 178 bytes

-2 from removing a debug tool

-5 from realizing that I'm using ES6 and can do away with parenthesis sometimes

-18 from removing something from an earlier version that is now obsolete

-1 from doing some sneaky stuff

-19 from removing unnecessary variables

-26 bytes from removing the all too complicated remove falsey values. I'm new to ES6

-1 from using shorter comparisons

-11 from using a recursive function

*-4 from replacing ?...:0 with &&..., and ... ${t} with ...+t This took way too much of my life, and didn’t give enough upvotes. but I am so glad the final code is a power of 2 (2^8) I do know there is another JavaScript answer that is about 120 bytes. but I still love this code EDIT: i don't know what i was thinking. 265 is not 2^8... While making this, I managed to break the ungolfed version. God, do I hate ungolfing code. EDIT 2: now it's looking like the better 121 byte solution y=(e,i,t="")=>i++<e?y(e,i,t+i+' '):t.slice(0,-1);m=(t,p)=>[p-1&&"prev",p<5?y(p-1,0):"1 ... "+y(p-1,p-3),[${t}],t-p<4?y(t,p):y(p+2,p)+ ... +t,t-p&&"next"].filter(e=>e).join


Explanation:

to come but basically y is range(end, start) and it does some cool stuff like:

1. show prev if page is 1
2. show left dots if page > 4
3. show right dots if total - page < 4
4. show next if total - page == 0

and stuff like that and just joins it by ' '. I know you don't have to but I like the fact that is semi-conventional. I don't know. Enjoy.

Try it online!

Validate it online!

Here's a 186 185 174 170 byte solution that I don't like: Try it online!