Code Golf - 根据当前页面生成附近的页码

时间:2010-07-29 03:18:07

标签: algorithm code-golf rosetta-stone

挑战在于创建一种算法,用于根据序列中的当前位置生成序列中特定大小的数字子集。

在Stack Overflow或Digg等繁忙网站上浏览多页内容时,通常需要让用户快速跳转到第一页,最后一页或特定页面他们正在查看的当前页面附近。

要求

  • 第一页和最后一页的页码始终显示
  • 页码的子集将 包含当前页码 以及之前和/或的页码 之后(取决于当前页面)
  • 页码的子集将 永远是固定数量的页面和 永远不会超过或不足 固定数量,除非:
    • totalPages < fixedWidth
  • 当前页面的位置 子集中的数字是固定的 除非:
    • 1 <= currentPage < (fixedWidth - defaultPostion)
    • (totalPages - currentPage) < (fixedWidth - defaultPostion)
  • 输出应指明何时有 第一个之间的差异大于0 数据页面和第一页 子集以及之间 子集的最后一页和最后一页 数据的。该指标应该出现 在任何一个位置最多一次。

如果您还无法想象,请查看问题/答案下的Stack Overflow配置文件。如果你有一个超过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] {{1}}

欢迎任何和所有语言的解决方案。

祝你好运!

14 个答案:

答案 0 :(得分:7)

Python - 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是当前页面否)

答案 1 :(得分:4)

GolfScript - 89 80 78个字符

~:&;\:C;:T,{-1%[T&-T)C-:C&2/-(]$0=:|1>{.1<\|>}*}2*]${{)]`[C]`/'[x]'*}%}%'...'*

样本I / O:

$ 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}

样本I / O:

$ 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]

答案 2 :(得分:3)

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]

答案 3 :(得分:2)

Common Lisp:262个重要字符

  

(defun [(n)(格式t“[〜a]”n))(defun p(cm&amp; key(s 5)(p 2))(let((l(max(min( - cp) )( - ms -1))1))(r(min(max(+ c( - p)s -1)s)m)))(当(> l 1)([1))(当( &gt; l 2)(princ“...”))(n从l到r的循环do([(if(= nc)#\ xn)))(当(&lt; r(1-m))( princ“...”))(当(&lt; rm)([m))))

未压缩:

(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)

答案 4 :(得分:1)

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).']');}

(排序)未经宣传:

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]),但会因此而变得不那么优雅。

答案 5 :(得分:1)

C#,240 / 195 184 chars

与其他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;
    }
}

答案 6 :(得分:1)

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";
}

答案 7 :(得分:0)

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页。 耸肩

答案 8 :(得分:0)

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]

答案 9 :(得分:0)

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]

答案 10 :(得分:0)

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]

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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>");
}
}

答案 13 :(得分:0)

Ruby 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