Shortlex中的那个数字是多少?


15

大多数计算机以二进制形式存储整数,但以十进制形式输出它们。但是,十进制只是一种表示形式,我们碰巧发现它很方便。

挑战是编写一些代码以shortlex十进制输出整数值。

那是什么?
http://en.wikipedia.org/wiki/Shortlex_order

Shortlex将数字序列的长度作为值的主要指示符。该序列从代表零的空字符串开始,为...

ε,0,1,...,8,9,00,01,...98,99,000,001,...,998,999,0000,...

(请考虑使用Excel列,但仅使用十进制数字。)

如上所述,编写一个程序或函数,该程序或函数接受一个整数并返回与该整数的shortlex小数表示形式相对应的字符串。

测试值:

0→“”(空字符串)
1→“ 0”
10→“ 9”
11→“ 00”
42→“ 31”
100→“ 89”
800→“ 689”
1060→“ 949”
10270→“ 9159”
100501→ “ 89390”


2
重要的是要注意,19, 20, 21, 22十进制中的序列映射到08, 09, 10, 11shortlex中。这就是为什么我感到困惑的原因100 -> 89
肖恩·莱瑟姆


6
请注意,您所说的数字的“ shortlex十进制”也是它的双射基十进制数字,用符号{0,1,2,3,4,5,6,7,8,9}代替常用数字{1,2,3,4,5,6,7,8,9,A}。例如,2014在通常的双射基十符号是1A14,并且在shortlex小数它是0903.
水库

Answers:


34

JavaScript(ES6)42 74

n=>(n-~(n+'').replace(/./g,8)+'').slice(1)

在FireFox控制台中测试

;[0,1,10,11,42,100,800,1060,10270,100501]
.forEach(x => console.log(x +" -> '" + S(x) + "'"))

输出量

0 -> ''
1 -> '0'
10 -> '9'
11 -> '00'
42 -> '31'
100 -> '89'
800 -> '689'
1060 -> '949'
10270 -> '9159'
100501 -> '89390'

我是怎么想的?

给定固定数量的数字,输出序列会简单地递增,因此输入和输出之间存在固定的增量。看一看:

  1..10 -> 0..9 (delta -1)
 11..110 -> 00..99 (delta -11)
111..1110 -> 000..999 (delta -111) mmm there's a pattern here...

但是前导0很难管理,因此我有一个标准的技巧,添加一个第一位数字并以模为模(即,切出输出中的第一位数字)。然后-1-> + 9,-11-> + 89,-111-> +889,依此类推。
最后一步:我不在乎第一个数字是什么,因此无需检查iinput数字是否小于或等于111 ...(坦白地说,我是通过反复试验发现的)

测试

var F=
n=>(n-~(n+'').replace(/./g,8)+'').slice(1)

function update()
{
  var i=+I.value
  O.textContent = F(i)
}


update()
<input id=I value=99 type=number oninput='update()'><pre id=O></pre>


8
我不知道为什么会这样。
Martin Ender 2014年

你为什么这样做n-~(n+'')只是代替n-~n
Claudiu 2014年

@Claudiu是(n+'').replace(...),replace适用于字符串,而不是数字。
edc65 2014年

@ edc65:糟糕,是的,现在才抓到它,不匹配我的括号。Dayum这真是太棒了
Claudiu

3
@Dennis可以随意移植。您已经赢了
edc65

13

Marbelous 177 173 170

@0@6000000@5
}0&0&0&0&0
>0@6&3
\\--\/&2
@0/\@4\/&1!!
@4@1..@2@5@3
IIIIIIIIIIII
FF&1FF&2FF&3
@1OO@2OO@3OO
:I
}1..}10001F7
=9&1++..&1&0
&0}0&1&0{1{1
{>\/{0//
:O
}0
+Z
+C
{0

由于Marbelous是8位语言,因此仅适用于256以下的值。

怎么运行的

Marbelous是一种2D语言,其值由8位大理石表示,该大理石在每个刻度上掉落一个单元格,除非某些设备阻止它们掉落。这个Marbelous计划包含3个委员会;让我们从最简单的一个开始:

:O
}0
+Z
+C
{0

:O是板的名称(准确地说,O是名称,并且:告诉解释器此行是名称。通过给板命名,其他板可以在其}0上调用的 是输入设备,这可以看作是此函数的参数。调用此函数时,此单元格将被输入大理石(值)替换。 +Z将35传递到经过它的大理石上并让其掉落。+C这样做相同,但只添加12。{0是一个输出单元格,当大理石到达此单元格时,该函数将退出并返回此输出设备中的值。

因此,总的来说,该评估板取一个值,然后加47。对我们来说,这意味着它将任何单个数字转换为数字-1的ASCII码(这当然也适用于10)。

:I
}1 .. }1 00 01 F7
=9 &1 ++ .. &1 &0
&0 }0 &1 &0 {1 {1
{> \/ {0 //

该板看起来有点复杂。您应该能够识别:I出板的名称,并找到一些输入和输出设备。您会注意到我们有两个不同的输入设备,}0}1。这意味着该功能需要2个输入。您还将注意到}1设备有两个实例。调用函数后,这两个单元格将包含相同的值。所述}0输入设备是一个直接上述\/装置中,这充当垃圾桶并除去在其上立即落入任何大理石。

让我们看一下}1输入设备放到板上的大理石中发生了什么:

}1
=9 &1
&0
{>

它将在第一次滴答声中掉落并击中=9设备。这会将大理石的值与9进行比较,如果语句=9评估为贯通,则使大理石通过。如果没有,大理石将被推到右边。&0并且&1是同步器。他们抓住掉落在上面的大理石,直到所有其他&n同步器都装满为止。如您所料,这将有条件地触发电路板其他部分的不同行为。

}1 00 01 F7
++ .. &1 &0
&1 &0 {1 {1
{0 //

如果我告诉您这++是一个增量器,则您应该已经能够知道将使用哪些不同的同步器。左边&1将包含输入值}1+ 1,&0其次将包含0(00是语言文字,以十六进制表示)。第二个&1将包含值1,右边&0将填充一个F7,从一个值中减去9,因为Marbelous中的加法为256模。

// 是一种偏转器设备,它将任何大理石推向左侧而不使其掉落。

将所有这些放在一起即可得到:如果大理石}1为9,则将&0充满同步器。这将导致值0落入{0输出,F7(或-9)落入{1输出。如果}1不是9,{0则将用}1+ 1 填充并{0包含1。还有一个{>设备,这是一种特殊的输出,它在木板旁边而不是在木板下面输出大理石。}1如果等于9,它将被填充。

@0 @6 00 00 00 @5
}0 &0 &0 &0 &0
>0 @6 &3
\\ -- \/ &2
@0 /\ @4 \/ &1 !!
@4 @1 .. @2 @5 @3
II II II II II II
FF &1 FF &2 FF &3
@1 OO @2 OO @3 OO

好吧,现在是大个子。该主板没有明确的名称,因为它是文件的主板。其隐式名称为Mb。您应该能够识别一些单元格。有一个输入设备,一些语言文字(00FF)。有一些同步器,还有一个偏转器。让我们一步一步地走过去。

@0 @6
}0 &0
>0 @6
\\ --
@0 /\ @4

因此,输入值(由于是主板,所以是命令行输入)从位于顶部的第二个单元格开始}0。它会掉落并到达>0另一个比较设备。任何大于0的大理石都将掉落,其他大理石将被推向右侧。(由于Marbelous变量是无符号的,因此只有恰好0会被推到右边)。然后,此零值大理石将撞击@6设备。这是一个门户,将大理石运送到另一个相应的门户,在此情况下位于其上方。然后,0大理石将到达&0同步器,并在其他位置触发一些操作。

如果大理石不为0,则大理石会掉落,然后通过\\撞击将其向右偏斜--,然后将其递减1,然后落入/\克隆器上。该设备取一枚大理石,并向右输出一个副本,向左输出一个副本。左边的一个将向上移动到另一个@0,大理石将再次通过该序列。左边的将带到其他地方。这给了我们一个循环,每个循环减少一次命令行输入,并在每个循环上触发一些行为,直到达到0。然后触发其他行为。

让我们看一下将大理石插入@4每个循环中会发生什么情况。

@4 @1 .. @2 @5 @3
II II II II II II
FF &1 FF &2 FF &3
@1 OO @2 OO @3 OO

这里(FF)有3种语言文字,它们将立即进入门户。这些门户会将它们带到其中三个II设备。II指的是:I我们在文件中进一步定义的董事会。由于:I具有2个不同的输入设备,因此在另一块板上的表示必须为2个单元宽。由于我们有6个包含的单元格II,因此我们可以告诉我们板上有3个此函数的实例。

FF(或256或-1,如果你会)弹珠会坐在输入细胞:I功能等待,直到有足够的输入大理石STO启动功能(多一个即是)。这就是@4门户的所在。递减的命令行输入的副本在每个循环中都从那里通过。这将触发最左边的:I板。初始值为256(或-1),并且无论命令行输入为-1。左边的大理石将被放入木板的}0装置中,右边的大理石将被放入:I木板的装置中}1。如果您回想起该委员会的工作,您将能够知道结果如何。它将在左侧输出上输出右侧输入的递增版本(并将9变成0,而不是10),并在右侧输出1或-9。

增量值将由门户网站直接带回到右侧输入单元格,右侧的值将落入同步器中。如果同步器已经装有大理石,则两个大理石将发生碰撞。碰撞的弹珠以256为模加在一起。因此,同步器中的值将遵循以下操作:它们开始为空,然后变为1、2、3、4、5、6、7、8、9、10,然后变为再次为1(因为247以模256为模加)。

您可能还记得,当输入值循环回到0时,弹子会向右输出。由于:I板子彼此相邻,因此将触发板子一次向右。这将使三个同步器的值高出一个值,该值比循环输入为0时作为命令行输入的shortlex表示形式高。

您可能还记得该:O函数将一个值转换为代表值-1的数字的ascii值。这些OO单元的输出将落在板上,然后将其相应的ascii字符打印到STDOUT。

00 00 00 @5
&0 &0 &0
&3
\/ &2
   \/ &1 !!
      @5

那么当命令行输入大理石达到0并填充&0同步器时会发生什么呢?好吧,一些0值的弹珠掉落并触发了三个同步器,这些同步器在板的底部保持shortlex数字的数字(+1)。&3最先被触发,因为它包含了最显著位,然后是&2其次&1。然后,该大理石会被传送到其他@5设备,最后撞到!!电池,从而终止了电路板。


4
看起来这似乎也可能是有效的Perl代码
Doorknob

12

CJam,14 11个字节

l40f-Ab)s1>

在线尝试。

怎么运行的

此方法主要基于edc65的答案(在获得他的明确许可的情况下):

" Read a line L from STDIN. ";

l

" edc65's answer now forms an integer N by replacing each digit in L by an 8 and computes
  L - ~N = L + N + 1. Instead of adding L and N, we subtract 40 from each char code of L.
  Since the char code of the digit `D` is `D + 48`, this basically adds 8 to each digit.  ";

40f-

" Turn the resulting array into an integer by considering its elements a base 10 number.
  This is implemented as A ↦ A[-1] + 10 * A[-2] + 100 * A[-3] + ⋅⋅⋅, so it won't choke
  on digits greater than the base.                                                        ";

Ab

" Increment the integer on the stack to complete the calculation of L + N + 1.            ";

)

" Push the integers string representation and discard its first character.                ";

s1>

运行示例

$ for i in 0 1 10 11 42 100 800 1060 10270 100501
> do echo $i: $(cjam <(echo 'l40f-Ab)s1>') <<< $i)
> done
0:
1: 0
10: 9
11: 00
42: 31
100: 89
800: 689
1060: 949
10270: 9159
100501: 89390

1
这是淫秽的
Claudiu 2014年

3
+1以寻求进一步缩短的方法
edc65

6

的Python 2(38)(43)

f=lambda n:n*'_'and f(~-n/10)+`~-n%10`

没有字符替代,只是算术。

取消高尔夫:

def f(n):
    if n==0: return ''
    else: return f((n-1)//10) + str((n-1)%10)

我没有很好的理由为什么递归有效,我只是将此模式适合值列表。如果将分别更改n-1n,则将获得常规的数字表示形式。

对于打高尔夫球,我使用比或更高的优先级~-n进行计算,以节省成本。该只是产生空当字符串和任何其他字符串,否则。该可以用于此目的的任何字符串。n-1/10%10n*'_'n=0'_'


4

Ruby,70 68 66 64 57字节

f=->n{i=-1;n-=10**i while n>=10**i+=1;i<1?'':"%0#{i}d"%n}

定义一个称为like的函数f[42]。这是该算法的大致分解:

  • 0分开对待。
  • 减去10的幂,直到下一个10的幂不再适合该数字。
  • 将数字变成左侧填充有零的字符串。

有关使用格式字符串的想法,请致谢Falko!


或者,使用edc65的方法:

f=->n{"#{n-~n.to_s.tr('^.',?8).to_i}"[1..-1]}

那是45个字节,我只包含它,因为我没有用它殴打他。;)


当然。我想我冗长的Python代码还是不会吸引您的。;)
Falko 2014年

@Optimizer我确定如果有人用一种高尔夫语言使用这种方法,他们的年龄会低于20。(也就是说,我用这种方法在Ruby中无法达到44,目前是45)
Martin Ender 2014年

2
@Optimizer我不同意。对于初学者来说,J和APL不是高尔夫语言,并且赢得的机会和GolfScript和CJam一样多。但此外,打高尔夫球不是关于绿色的勾号,而是关于“在您的联盟中”击败提交的人。如果我编写的Ruby提交文件击败了这4种语言,那么我对此会感到非常高兴,并且我并不需要禁止那些人使用更冗长的语言来打高尔夫球。实际上,像edc这样的“普通”语言中的聪明高尔夫比单纯的(但更短)高尔夫语言实现更有可能获得很多好评。
Martin Ender 2014年

3

Haskell,67个字节

n('9':x)='0':n x
n(c:x)=succ c:x
n""="0"
f x=reverse$iterate n""!!x

此解决方案基本上以简写表示法将给定的次数加1。

用法:

>f 9
"8"
>f 100
"89"

3

CJam,16个字节

li_)9*,{`1>}%_&=

在线尝试。至少需要O(n)的时间和内存,因此将100501留给离线解释器...

怎么运行的

这种方法的基本思想是按自然顺序计算至少N个shortlex小数,并丢弃除Nth外的所有小数。不是很有效,但是很短。

li                " Read an integer N from STDIN.                                   ";
  _)9*            " Push M := (N + 1) * 9.                                          ";
      ,           " Push A := [ 0 1 ... M - 1 ].                                    ";
       {   }%     " For each I ∊ A:                                                 ";
       {`1>}%     " Push its string representation and discard the first character. ";
             _&   " Remove duplicates from the resulting array.                     ";
               =  " Retrieve the Nth element.                                       ";

运行示例

$ for i in 0 1 10 11 42 100 800 1060 10270 100501
> do echo $i: $(cjam <(echo 'li_)9*,{`1>}%_&=') <<< $i)
> done
0:
1: 0
10: 9
11: 00
42: 31
100: 89
800: 689
1060: 949
10270: 9159
100501: 89390

3

Bash + coreutils,27个字节

@ edc65很聪明的回答,用@丹尼斯的改进

cut -b2-<<<$[$1-~${1//?/8}]

输出:

$ for n in 0 1 10 11 42 100 110 111 800 1060 1110 1111 10270 100501; do echo "./shortlex.sh $n = \"$(./shortlex.sh $n)\""; done
./shortlex.sh 0 = ""
./shortlex.sh 1 = "0"
./shortlex.sh 10 = "9"
./shortlex.sh 11 = "00"
./shortlex.sh 42 = "31"
./shortlex.sh 100 = "89"
./shortlex.sh 110 = "99"
./shortlex.sh 111 = "000"
./shortlex.sh 800 = "689"
./shortlex.sh 1060 = "949"
./shortlex.sh 1110 = "999"
./shortlex.sh 1111 = "0000"
./shortlex.sh 10270 = "9159"
./shortlex.sh 100501 = "89390"
$ 

先前的答案:

Bash + coreutils,71个 54字节

这是一种稍微不同的方法:

jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed $1!d 2>-
  • jot 输出递增的十六进制整数
  • tr 将此转换为(0,1,...,8,9,b,... f,0a,00,01,...,99,9b,...,ff,0aa,...,000 ,...)
  • grep 只需过滤所有包含数字的行即可得出(0,1,...,8,9,00,...,99,000 ....)
  • sed 删除除第n行外的所有内容
  • STDERR重定向到丢弃文件“-”,以便我们在传入0时简单地得到一个空字符串(sed对从1开始的行号进行计数,因此如果传入0则报错)
  • 因为我们要过滤掉带有的数字grep,所以我们需要使用seq/ 生成dc比输入数字更多的以11为底的整数。重复n的数字已绰绰有余。

请注意,在打印出shortlex数字之后,我会seq继续生成最大为的数字$1$1,这特别是对于较大的输入数字来说会很慢-O(n²)。我们可以seq在打印后立即退出以7字节为代价来加快速度:

jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed -n $1{p\;q} 2>-

问题中没有速度要求,因此我主要选择较短的版本。


@Optimizer不:尝试s='jot -w%x $1$1|tr 0-9a a0-9|grep -P ^\\d+$|sed $1!d 2>-'; echo ${#s}。我怀疑您可能使用python来测量字符串长度,该字符串将“ \\”视为一个字符。
Digital Trauma 2014年

2
到目前为止,我的答案已经改变,但是如果我在第一版中做了一些聪明的事情,那完全是偶然的。这是edc65的直接回答。8都是他的...- $a似乎不需要辅助变量;cut -b2-<<<$[$1-~${1//?/8}]应该工作正常。
丹尼斯

1
@丹尼斯对,我明白了。谢谢你的建议!
Digital Trauma 2014年

2

Python 2-84、70 66

n=input()
i=0
while n>=10**i:n-=10**i;i+=1
print"%%0%dd"%i%n*(i>0)

替代方法(相同长度):

n=input()
k=len(`9*(n+1)/10`)
print"%%0%dd"%k%(n-int('1'*k))*(n>0)

使用格式字符串很聪明!希望您也不要介意我也使用它。:)
Martin Ender 2014年

2

Python 3,107个字符

这并没有最终获得胜利,但我认为这很聪明:

def G():yield'';yield from(r+c for r in G()for c in'0123456789')
S=lambda n:list(zip(range(n+1),G()))[n][1]

我用64个字符定义了整个序列的生成器。不幸的是,我必须经过一些扭曲才能获得生成器的第n个元素……如果我能做的话S=lambda n:G()[n]


2

珀斯 12

@ edc65的另一个答案是谁是明显的获胜者(IMO):

t`+hQv*l`Q\8

测试包(感谢@DigitalTrauama):

$ for n in 0 1 10 11 42 100 110 111 800 1060 1110 1111 10270 100501; do echo "shortlex.pyth $n = \"$(pyth programs/shortlex.pyth <<< $n)\""; done
shortlex.pyth 0 = ""
shortlex.pyth 1 = "0"
shortlex.pyth 10 = "9"
shortlex.pyth 11 = "00"
shortlex.pyth 42 = "31"
shortlex.pyth 100 = "89"
shortlex.pyth 110 = "99"
shortlex.pyth 111 = "000"
shortlex.pyth 800 = "689"
shortlex.pyth 1060 = "949"
shortlex.pyth 1110 = "999"
shortlex.pyth 1111 = "0000"
shortlex.pyth 10270 = "9159"
shortlex.pyth 100501 = "89390"

说明:

Q = eval(input())             Implicit.
t`                            All but the first digit of
  +hQ                         Q+1 + 
   v                          eval(
    *l`Q                      len(repr(Q)) * 
     \8                       "8"

CJam对Pyth;战斗还在继续。:P
丹尼斯

我尝试给Pyth挑战一下,但找不到将List转换为整数的方法(例如[8, 8, 9] -> 889)。你是怎样做的?
丹尼斯

@Dennis要从列表到整数,您基本上必须经过字符串。jk会将您的列表转换为字符串,并将v其转换为整数。因此,vjk[8 8 9]将给予数889
isaacg

好,谢谢。可悲的是,字符串转换使一些技巧变得不可能。使用CJam / GolfScript基本转换,[2 -1] -> 19以及[1 11] -> 21
丹尼斯2014年

1
@Dennis是的,一旦我实际上将基本转换添加到Pyth,就可以了。但是我还没有。
isaacg 2014年


1

Haskell,57个字节

((g=<<[0..])!!)
g 0=[""]
g n=[c:s|c<-['0'..'9'],s<-g$n-1]

在线尝试!

构造一个shortlex数字的无限列表,并为该索引建立索引。g n通过在上一代的每个数字前面加上下一位来构造数字的第n代。



0

Excel,37个字节

使用@ edc65的方法:

=REPLACE(REPT(8,LEN(A1))+A1+1,1,1,"")

0

果冻,5字节

ḃ⁵ịØD

在线尝试!

我是Jelly的新手,因此,如果您可以改善这一点,请发表评论!

说明:

ḃ⁵ịØD   Main link.
ḃ       Convert to bijective base ...
 ⁵      10.
  ị     Each number (1 - 10) is converted to the character at its index in the string...
   ØD   “0123456789” (digits)

(根据上面res的评论,问题等同于将数字转换为双射基数10)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.