Code Golf - генерирует номера соседних страниц на основе текущей страницы
Задача состоит в том, чтобы создать алгоритм для генерации подмножества чисел определенного размера в последовательности на основе текущей позиции в этой последовательности.
При навигации по многим страницам контента на загруженном сайте, таком как переполнение стека или Digg, часто желательно дать пользователю возможность быстро перейти к первой странице, последней странице или конкретной странице, которая находится рядом с текущей страницей, которой они являются. просмотр.
Требования
- Номера первой и последней страницы отображаются всегда
- Подмножество номеров страниц будет содержать номер текущей страницы, а также номера страниц до и / или после него (в зависимости от текущей страницы)
- Подмножество номеров страниц всегда будет фиксированным числом страниц и никогда не может превышать или не соответствовать этому фиксированному числу, если только:
totalPages < fixedWidth
- Положение номера текущей страницы в подмножестве является фиксированным, если:
1 <= currentPage < (fixedWidth - defaultPostion)
или же(totalPages - currentPage) < (fixedWidth - defaultPostion)
- Вывод должен указывать, когда существует разница больше 0 между первой страницей данных и первой страницей подмножества, а также между последней страницей подмножества и последней страницей данных. Этот индикатор должен появляться не более одного раза в любой позиции.
Если вы еще не можете представить это, взгляните на свой профиль переполнения стека в разделе вопросы / ответы. Если у вас есть более 10 из них, вы должны увидеть ссылки внизу, которые генерируются именно таким образом. Или прокрутите страницу вниз до http://digg.com/ и посмотрите, как они управляют страницами.
Примеры
Все примеры предполагают размер подмножества 5 и текущую страницу в позиции 3, но они должны быть настраиваемыми в вашем решении. ...
указывает на разрыв между номерами страниц, [x]
указывает на текущую страницу.
Текущая страница: 1 из 30
Выход: [x][2][3][4][5]...[30]
Текущая страница: 2 из 30
Выход: [1][x][3][4][5]...[30]
Текущая страница: 13 из 30
Выход: [1]...[11][12][x][14][15]...[30]
Текущая страница: 27 из 30
Выход: [1]...[25][26][x][28][29][30]
Текущая страница: 30 из 30
Выход: [1]...[26][27][28][29][x]
Текущая страница: 3 из 6
Выход: [1][2][x][4][5][6]
Текущая страница: 4 из 7
Выход: [1][2][3][x][5][6][7]
Дополнительные разъяснения
- Первая и последняя страницы не учитываются
numberOfPages
если они не являются последовательно частьюnumberOfPages
как в[1][x][3][4][5]...[30]
или же[1]...[26][27][28][x][30]
, но не в[1]...[8][9][x][11][12]...[30]
- Индикатор пропуска не должен быть включен, если расстояние между концом подмножества и первой или последней страницей меньше 1. Таким образом, можно иметь непрерывную последовательность страниц до
fixedWidth + 2
как в[1][2][3][x][5][6]...[15]
или же[1][2][3][x][5][6][7]
Решения на всех языках приветствуются.
Удачи!
14 ответов
Питон - 156 182 140 символов
f=lambda c,m,n:'...'.join(''.join((' ','[%s]'%(p,'x')[p==c])[min(m-n,c-1-n/2)<p<max(n+1,c+1+n/2)or p in(1,m)]for p in range(1,m+1)).split())
И тестирование на примерах в OP:
for c, m, expect in (
(1, 30, "[x][2][3][4][5]...[30]"),
(2, 30, "[1][x][3][4][5]...[30]"),
(13, 30, "[1]...[11][12][x][14][15]...[30]"),
(27, 30, "[1]...[25][26][x][28][29][30]"),
(30, 30, "[1]...[26][27][28][29][x]"),
(3, 6, "[1][2][x][4][5][6]"),
(4, 7, "[1][2][3][x][5][6][7]"),
):
output = f(c, m, 5)
print "%3d %3d %-40s : %s" % (c, m, output, output == expect)
Спасибо за комментарии.:)
PS. сильно отредактировано, чтобы уменьшить количество символов и добавить n
= количество страниц вокруг текущей (m
максимальное количество страниц и c
текущей страницы нет)
GolfScript - 89 80 78 символов
~:&;\:C;:T,{-1%[T&-T)C-:C&2/-(]$0=:|1>{.1<\|>}*}2*]${{)]`[C]`/'[x]'*}%}%'...'*
Пример ввода / вывода:
$ echo "27 30 5"|golfscript page_numbers.gs
[1]...[25][26][x][28][29][30]
Вывод для всех номеров страниц занимает 83 символа (незначительные изменения в основной части).
~:&;:T,{:C;T,{-1%[T&-T(C-:C&2/-]$0=:|1>{.1<\|>}*}2*]${{)]`[C)]`/'[x]'*}%}%'...'*n}
Пример ввода / вывода:
$ echo "7 5"|golfscript page_numbers.gs
[x][2][3][4][5]...[7]
[1][x][3][4][5]...[7]
[1][2][x][4][5]...[7]
[1][2][3][x][5][6][7]
[1]...[3][4][x][6][7]
[1]...[3][4][5][x][7]
[1]...[3][4][5][6][x]
$ echo "7 3"|golfscript page_numbers.gs
[x][2][3]...[7]
[1][x][3]...[7]
[1][2][x][4]...[7]
[1]...[3][x][5]...[7]
[1]...[4][x][6][7]
[1]...[5][x][7]
[1]...[5][6][x]
F#! - 233 значимых персонажа.
Все опции поддерживаются и в пределах спецификации.
Программа:
let P c b n f m s =
let p = b/2
let u = max 1 (if n-b <= c-p then n-b+1 else max 1 (c-p))
let v = min n (if b >= c+p-1 then b else min n (c+p))
let P = printf
let C c a n = if c then P a n
C (u > 1) f 1
C (u = 3) f 2
C (u > 3) "%s" s
let I = Seq.iter (P f)
I {u .. c-1}
P "%s" m
I {c+1 .. v}
C (n - 2 > v) "%s" s
C (v = n - 2) f (n-1)
C (n > v) f n
Тестовое задание:
for p in 1..6 do
P p 5 30 "[%d]" "[x]" "..."
printfn ""
for p in 25..30 do
P p 5 30 "[%d]" "[x]" "..."
printfn ""
Выход:
[x][2][3][4][5]...[30]
[1][x][3][4][5]...[30]
[1][2][x][4][5]...[30]
[1][2][3][x][5]...[30]
[1][2][3][4][x][6][7]...[30]
[1]...[4][5][x][7][8]...[30]
[1]...[23][24][x][26][27]...[30]
[1]...[24][25][x][27][28][29][30]
[1]...[26][x][28][29][30]
[1]...[26][27][x][29][30]
[1]...[26][27][28][x][30]
[1]...[26][27][28][29][x]
Общий Лисп: 262 значимых персонажа
(defun [(n)(формат t"[~a]"n))(defun p(c m &key(s 5)(p 2))(let((l(max(min(- c p)(- m s -1))1))(r(min(max(+ c(- p)s -1)s)m)))(когда (> l 1)([ 1))(когда (> l 2)(princ"..."))(цикл для n от l до r do([ (if(= n c)#\x n)))(когда (
несжатый:
(defun print[] (n)
(format t "[~a]" n))
(defun page-bar (current max &key (subset-size 5) (current-position 2))
(let ((left (max (min (- current current-position)
(- max subset-size -1))
1))
(right (min (max (+ current (- current-position) subset-size -1)
subset-size)
max)))
(when (> left 1) (print[] 1))
(when (> left 2) (princ "..."))
(loop for p from left upto right
do (print[] (if (= p current) #\x p)))
(when (< right (1- max)) (princ "..."))
(when (< right max) (print[] max))))
Тестирование:
CL-USER> (mapc (lambda (n) (p n 7) (format t "~%")) '(1 2 3 4 5 6 7))
[x][2][3][4][5]...[7]
[1][x][3][4][5]...[7]
[1][2][x][4][5]...[7]
[1][2][3][x][5][6][7]
[1]...[3][4][x][6][7]
[1]...[3][4][5][x][7]
[1]...[3][4][5][6][x]
(1 2 3 4 5 6 7)
CL-USER> (p 1 1)
[x]
NIL
CL-USER> (p 1 2)
[x][2]
NIL
CL-USER> (p 0 0)
NIL
CL-USER> (p 0 1)
[1]
NIL
CL-USER> (p 0 30)
[1][2][3][4][5]...[30]
NIL
CL-USER> (p 31 30)
[1]...[26][27][28][29][30]
NIL
Размер подмножества и положение текущей страницы в этом подмножестве могут быть заданы в необязательных параметрах (:current-position
естественно, начинается с нуля внутри подмножества):
CL-USER> (page-bar 8 15 :subset-size 6 :current-position 5)
[1]...[3][4][5][6][7][x]...[15]
NIL
РЕДАКТИРОВАТЬ: вызов в сжатой версии будет:
CL-USER> (p 8 15 :s 6 :p 5)
C#,240/195 184 символа
Похож на другой ответ C#, но с некоторым неприятным побочным эффектом, заполненным LINQ. Я полагаю, что это может быть несколько короче.
void Pages(int p,int t,int s) {
int h=s/2,l=0;
foreach(var c in Enumerable.Range(1,t).Where(x=>x==1||x==t||(p+h<s&&x<=s)||(p-h>t-s&&x>t-s)||(x>=p-h&&x<=p+h)).Select(x=>{Console.Write((x-l>1?"...":"")+(x==p?"[X]":"["+x+"]"));l=x;return x;}));
}
Редактировать:
Оказывается, императивная версия короче с хорошим запасом (195 184 символа):
void Pages(int p,int t,int s){
int h=s/2,l=0,i=1;
for(;i<=t;i++)
if(i==1||i==t||p+h<s&&i<=s||p-h>t-s&&i>t-s||i>=p-h&&i<=p+h){
Console.Write((i-l>1?"...":"")+(i==p?"[X]":"["+i+"]"));
l=i;
}
}
Perl, 92 символа
$_=join'',map{$_==1||$_==$n||abs($_-$x)<=$a?$_==$x?'[x]':"[$_]":'_'}(1..$n);s/_+/.../g;print
Полный тест:
@i=(
[1,30,2],
[2,30,2],
[13,30,2],
[27,30,2],
[30,30,2],
[3,6,2],
[4,7,2]
);
for$r(@i)
{
($x,$n,$a)=@$r;
$_=join'',map{$_==1||$_==$n||abs($_-$x)<=$a?$_==$x?'[x]':"[$_]":'_'}(1..$n);s/_+/.../g;print
;print"\n";
}
PHP, 234 символа
function pages($t,$c,$s=5){$m=ceil($s/2);$p=range(1,$t);$p[$c-1]='x';$a=array();return preg_replace('~(\[('.implode('|',array_merge($c-$m<2?$a:range(2,$c-$m),$t-1<$c+$m?$a:range($c+$m,$t-1))).')\])+~','...','['.implode('][',$p).']');}
(В некотором роде) unminified:
function pages($max, $current, $subset=5) {
$m = ceil($subset / 2); // amount to go in each direction
$arr = range(1, $max); // array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
$arr[$current-1] = 'x'; // array(1, 2, 3, 4, x, 6, 7, 8, 9, 10)
// replace ~(\[(2|8|9)\])+~ with ...
$pattern = '~(\[(' . implode('|', array_merge($current-$m >= 2 ? range(2, $current-$m) : array(), $max-1 >= $current+$m ? range($current+$m, $max-1): array())) . ')\])+~';
return preg_replace($pattern, '...', '['.implode('][',$arr).']');
}
Это не совсем соответствует спецификации ([1][x][3][4]...[30]
вместо [1][x][3][4][5]...[30]
), но это стало бы намного менее изящным с учетом этого.
Python - 334 символа - полная функциональность
Я понимаю, что более короткий ответ уже был опубликован, но он не поддерживает настраиваемую ширину и положение в подмножестве страниц. Мой делает.
def paginator(c, n, w, o):
b = range(c-w/2+o,c+w/2+1+o)
b = [e+abs(b[0])+1 for e in b]if b[0]<=0 else[e-abs(n-b[w-1])for e in b]if b[w-1]>n else b
p = ([]if 1 in b else[1])+b+([]if n in b else[n])
return ''.join(('...'if p[i]-p[i-1]!=1 and i>0 and i<len(p)else'')+'[%d]'%p[i]if p[i]!=c else'[x]'for i in range(len(p)))
И вот тесты, которые все проходят
if __name__ == '__main__':
for current, n, width, offset, expect in (
(1, 30, 5, 0, "[x][2][3][4][5]...[30]"),
(2, 30, 5, 0, "[1][x][3][4][5]...[30]"),
(13, 30, 5, 0, "[1]...[11][12][x][14][15]...[30]"),
(13, 30, 5, 1, "[1]...[12][x][14][15][16]...[30]"),
(13, 30, 5, -1, "[1]...[10][11][12][x][14]...[30]"),
(27, 30, 5, 0, "[1]...[25][26][x][28][29][30]"),
(30, 30, 5, 0, "[1]...[26][27][28][29][x]"),
(30, 30, 5, 1, "[1]...[26][27][28][29][x]"),
(3, 6, 5, 0, "[1][2][x][4][5][6]"),
(3, 6, 5, -1, "[1][2][x][4][5][6]"),
(3, 6, 5, 1, "[1][2][x][4][5][6]"),
(4, 7, 5, 0, "[1][2][3][x][5][6][7]"),
):
output = paginator(current, n, width, offset)
print "%3d %3d %3d %3d %-40s : %s" % (current, n, width, offset, output, output == expect)
print ''
Это мой первый код-гольф, классная штука, отныне буду делать гораздо больше:P
C# 278 символов
программа
void Pages(int c,int t,int w){
int p=(w/2)+1;
int b=c-p;
int f=c+(w-p);
if(b<0){
f+=b*-1;
}else if(f>t){
b-=f-t;
f=t;
}
for(int i=1;i<=t;i++){
if(t<=w||(i==1||i==t)||(i>b&&i<=f))
Console.Write(i==c?"[X]":"[{0}]",i);
else if(t>w&&(i==b||i==f+1))
Console.Write("...");
}
}
Тестовое задание
for(int i=1;i<=5;i++) {
Pages(i,5,5);
Console.WriteLine();
}
for(int i=1;i<=15;i++) {
Pages(i,15,5);
Console.WriteLine();
}
Выход
[X][2][3][4][5]
[1][X][3][4][5]
[1][2][X][4][5]
[1][2][3][X][5]
[1][2][3][4][X]
[X][2][3][4][5]...[15]
[1][X][3][4][5]...[15]
[1][2][X][4][5]...[15]
[1][2][3][X][5][6]...[15]
[1]...[3][4][X][6][7]...[15]
[1]...[4][5][X][7][8]...[15]
[1]...[5][6][X][8][9]...[15]
[1]...[6][7][X][9][10]...[15]
[1]...[7][8][X][10][11]...[15]
[1]...[8][9][X][11][12]...[15]
[1]...[9][10][X][12][13]...[15]
[1]...[10][11][X][13][14][15]
[1]...[11][12][X][14][15]
[1]...[11][12][13][X][15]
[1]...[11][12][13][14][X]
Javascript - 398 393 символа
Рабочая функция
v(j, o, l)
, где:
j
это номер страницыo
общее количество страницl
количество отображаемых страниц (размер подмножества)
v(10, 30, 5)
возвращает: [1]...[8][9][x][11][12]…[30]
function v(j,o,l){function k(q){return q.length}function y(n,m){t=[];while(n<=m){t.push(n);n++}return t}r=y(1,j-1);g=y(j+1,o);b=k(r);a=k(g);c=l/2;(b>l/2&&a>=c)?r=r.splice(-l/2):((a<=c)?r=r.splice(-l+a+1):0);b=k(r);g=g.slice(0,l-1-b);a=k(g);r.push("x");g[a-1]==o-1?g.push(o):0;r[0]==2?r.unshift(1):0;r=r.concat(g);return(r[0]>2?"[1]...":"")+"["+r.join("][")+"]"+(g[k(g)-1]<o-1?"...["+o+"]":"")}
Несжатая версия
function run(cp, tp, l) {
function y(n,m){t=[];while(n<=m){t.push(n);n++}return t};
var before=y(1, cp-1);
var after=y(cp+1, tp);
var b=before.length;
var a=after.length;
var c=Math.floor(l/2);
if (b>l/2 && a>=c) {
before=before.splice(-l/2);
} else if (a<=c) {
before=before.splice(-(l-a)+1);
}
b=before.length;
after=after.slice(0, l-1-b);
a=after.length
before.push("x");
if (after[a-1]==tp-1)
after.push(tp);
if (before[0]==2)
before.unshift(1);
before=before.concat(after);
// Add bounds to either side
var pre=["",""];
if (before[0]>2) pre[0]="[1]...";
if (after[after.length-1]<tp-1) pre[1]="...["+tp+"]";
return pre[0]+"["+before.join("][")+"]"+pre[1];
}
Простая тестовая функция
function testValues() {
var ts=[1, 30, "[x][2][3][4][5]...[30]",
2, 30, "[1][x][3][4][5]...[30]",
13, 30, "[1]...[11][12][x][14][15]...[30]",
27, 30, "[1]...[25][26][x][28][29][30]",
30, 30, "[1]...[26][27][28][29][x]",
3, 6, "[1][2][x][4][5][6]",
4, 7, "[1][2][3][x][5][6][7]"];
for (var i=0; i<ts.length; i+=3) {
var rr=v(ts[i], ts[i+1], 5);
document.write(ts[i]+" of "+ts[i+1]+": "+rr+" |Correct-> "+ts[i+2]+"<br>");
ts[i+2]==rr ? document.write("<span style='color:green'>Check!</span>") : document.write("<span style='color:red'>Fail</span>");
document.write("<br><br>");
}
}
Python - 321 символов
Я предполагаю, что вы печатаете на текущей странице и общее количество страниц в командной строке (stdin):
import sys
p=sys.stdout.write
c,t=raw_input().split()
c,t=int(c),int(t)
r=range(1,t+1)
l=len(r)
p("[1]")
if c>7:
p("...")
for n in r[c-3:c+2]:
if n==1:continue
if n-t==-5 and l>7:continue
if c==n:n="X"
p("[%s]"%n)
if l<7:
for n in range(2,6):
if c==n:n="X"
p("[%s]"%n)
if r[c+2]<t and l>6:
p("...")
p("[%d]"%t)
Не совсем в гольфе (только короткие имена), поэтому я ожидаю, что лучшее решение будет по крайней мере вдвое меньше.
пример
python pag.py
3 30
[1][2][X][4][5]...[30]
Редактировать: я понимаю, что это не так для вещи, как "2 4" или "2 2" - это предполагает, по крайней мере, 6 страниц. пожимание плечами
Руби 1.9.1 - 114
for x,n,w in [[1,30,5],[2,30,5],[13,30,5],[27,30,5],[30,30,5],[3,6,5],[4,7,5]]
puts (1..n).map{|i|i>[-w/2+x,n-w].min&&i<=[x+w/2,w].max||i==1||i==n ?"[#{i==x ?'x':i}]":'-'}.join.gsub(/-+/,'...')
end
Groovy: 242 232 символа, поддерживает настраиваемую длину группы
Синтаксис вызова: Paging(currentOffset, totalWidth, groupSize)
def(c,t,g)=args.collect{it.toInteger()};def p,s=Math.max(c-(g/2).toInteger(),1);p='['+((c==1?'x':1)+(s>2?']...':']'));(s..Math.min(s+g-1,t)).each{if(it>1&&it<t)p+='['+(c==it?'x':it)+']'};print p+(t>s+g?'...[':'[')+(t==c?'x':t)+']';
Читаемая версия:
def (c,t,g) = args.collect{it.toInteger()};
def p,s = Math.max(c - (g/2).toInteger(), 1);
p = '['+((c==1?'x':1)+(s>2?']...':']'));
(s .. Math.min(s+g-1,t)).each{
if(it > 1 && it < t)
p += '[' + (c == it ? 'x' : it) + ']'
};
print p + (t > s + g ? '...[' : '[') + (t==c ? 'x' : t) + ']';
Называя это так:
Paging ([1, 20, 5])
println '';
Paging ([10, 20, 5])
println '';
Paging ([20, 20, 5])
println '';
Paging ([7, 17, 3])
println '';
Paging ([2, 228, 3])
println '';
Paging ([2, 5, 3])
println '';
Paging ([1, 5, 5])
дает такие результаты:
[x][2][3][4][5]...[20]
[1]...[8][9][x][11][12]...[20]
[1]...[18][19][x]
[1]...[6][x][8]...[17]
[1][x][3]...[228]
[1][x][3]...[5]
[x][2][3][4][5]
Ruby 1,9 - 197 символов
p,s,t=$*.map &:to_i
a=p-s/2
e=a+s-1
a<1&&(e+=1-a;a=1)
e>t&&(a-=e-t;e=t)
s>=t&&(a=1;e=t)
m=(a..e).map{|n|"[#{n==p ??x:n}]"}.join
a>2&&m='...'+m
a>1&&m='[1]'+m
e<t-1&&m<<'...'
e<t&&m<<"[#{t}]"
puts m
Использование: ruby pager.rb [position] [sampleSize] [totalWidth]