CJam高尔夫技巧


43

CJam是一种受GolfScript启发的基于堆栈的高尔夫语言,由PPCG用户aidtsu创建。

因此,就其他特定于语言的提示问题而言:

您在CJam打高尔夫球有哪些一般秘诀?请为每个答案发布一个提示


4
另请参见GolfScript中打高尔夫球的技巧;这些语言非常相似,因此许多技巧都可以采用任何一种方式进行调整。
Ilmari Karonen 2014年

2
@IlmariKaronen在回答了该问题的答案之后,由于语言的语法或逻辑差异,我只能说其中大约一半适用于CJam。
Optimizer

Answers:


23

正确的模数为负数

通常,取模运算的结果与第一个操作数的符号相同是令人讨厌的。例如,-5 3%给出-2而不是1。通常,您不希望后者。天真的解决方法是应用模,一次添加除数,然后再次应用模:

3%3+3%

但这又长又丑。相反,我们可以使用以下事实:数组索引始终是模块化的,并且可以正确地与负索引一起使用。因此,我们只需将除数变成一个范围并访问该范围:

3,=

应用于-5,这给出1了预期的结果。而且它仅比内置长一个字节%

如果模数是2的幂,则可以使用按位算术(这也快很多)来保存另一个字节。相比:

32,=
31&

对于特殊情况,65536 == 2^16可以通过使用字符类型的包装行为来保存另一个字节:

ci

13

推送串联的字符范围

  • 包含所有数字的字符串"0123456789"可以写成

    A,s
    
  • 大写ASCII字母(A-Z)可以按

    '[,65>
    

    它会生成所有字符(最多Z个)的字符串,然后丢弃前65个字符(最多@)。

  • 所有ASCII字母(A-Za-z)均可按

    '[,65>_el+
    

    如上操作,然后创建一个副本,转换为小写并追加。

    但是,有一种更短的方法!

    然后经常被忽略的^运算符(列表的对称差异)允许在保留三个字节的同时创建相同的范围:

    '[,_el^
    

    '[,创建所有ASCII字符到Z的范围,_el创建小写副本,并^仅保留两个字符串中出现在一个中的字符,但不同时出现在两个中。

    由于第一个字符串中的所有字母均为大写字母,第二个字符串中的所有字母均为小写字母,并且两个字符串中的所有非字母字符都包含在字符串中,因此结果为字母字符串。

  • A-Za-z0-9+/可以使用上述技术并添加非字母来推送RFC 1642 Base64字母():

    '[,_el^A,s+"+/"+
    

    同样短的推入字符串的方法仅利用对称差异:

    "+,/0:[a{A0":,:^
    

    我们如何在开头找到字符串?

    所有使用的字符范围(A-Za-z0-9+/)可以被推作为到范围对称差开始在空字节,即'A,'[,^'a,'{,^'0,':,^'+,',,^'/,'0,^

    因此,执行:,:^"A[a{):+,/0"将推动期望的字符,但不能以正确的顺序。

    我们如何找到正确的订单?蛮力抢救!该程序

    '[,_el^A,s+"+/"+:T;"0:A[a{+,/0"e!{:,:^T=}=
    

    遍历字符串的所有可能排列,应用:,:^并将结果与​​所需的输出(permalink)进行比较。

  • .-9A-Za-z可以使用上述方法来生成例如由crypt()使用的基数64字母:

    ".:A[a{":,:^
    

    这是我知道的最短的方法。

    由于所需输出中的所有字符均为ASCII顺序,因此不需要遍历排列。

  • 并非可以使用来按所需顺序推送所有串联的字符范围:,:^

    例如,0-9A-Za-z;-?不能通过:,:^对进行任何排列来推动范围"0:A[a{;@"

    但是,通过使用代码,我们可以找到所需字符串的旋转变体

    A,'[,_el^'@,59>]s2*:T;"0:A[a{;@"e!{:,:^T\#:I)}=Ip
    

    它将打印(永久链接)以下内容:

    10
    0:@[a{A;
    

    这意味着

    "0:@[a{A;":,:^Am>
    

    与...具有相同的效果

    A,'[,_el^'@,59>]s
    

    只能在不加[。的情况下用于空堆栈。


11

避免{…} {…}?

假设您在堆栈上有一个整数。如果是奇数,则要将其乘以3并加1;否则,请为0。否则,您要将其除以2。

“正常”的if / else语句如下所示:

_2%{3*)}{2/}?

但是,使用块通常不是可行的方法,因为{}{}已经添加了四个字节。?也可以用于选择堆栈中的两个项目之一:

_2%1$3*)@2/?

这少了一个字节。


块-?空的if语句始终是不可行的。例如,

{}{2/}?

比2个字节长

{2/}|

相反,如果你有

{2/}{}?

并且您要检查的是非负整数,您可以执行

g)/

新的{}&{}|方便的,但是如果您不能使堆栈混乱,则有时会出现问题。

不过,在

_{…}{;}?

您可以改用临时变量:

:T{T…}&

1
!)/并且g)/在示例中更短。
jimmy23013

11

切换语句

CJam没有switch语句。嵌套的if语句也可以正常工作,但是{{}{}?}{}?已经是12个字节长...

如果可以将条件转换为较小的非负整数,则可以将所有case语句转换为带分隔符的字符串并评估相应的结果。

例如,如果我们想执行code0如果堆栈的整数是0code1如果它是1,并且code2如果它是2,我们既可以使用

_{({code2}{code1}?}{;code0}?

要么

[{code0}{code1}{code2}]=~

要么

"code0 code1 code2"S/=~

S/将字符串拆分为["code0" "code1" "code2"]=提取相应的块,然后~评估代码。

单击此处查看运行中的switch语句。

最后,正如@ jimmy23013和@RetoKoradi所建议的那样,在某些情况下,我们甚至可以缩短开关的时间。说code0code1code2具有长度大号0大号1大号2分别。

如果大号0 = L 1 ≥大号2

"code0code1code2"L/=~

可以替代地被使用,其中L大号0。而不是在定界符处分割,而是在/这里将字符串分割成相等长度的块。

如果大号0 ≥大号1 ≥大号2 ≥大号0 - 1

"cccooodddeee012">3%~

可以代替使用。>从字符串的开头删除0、1或2个元素,并3%提取每第三个元素(从第一个元素开始)。


对于最后一个示例,相对于此,是否有任何优势 "code0code1code2"5/=~?对我来说似乎更直接,而且长度相同。
Reto Koradi

@RetoKoradi如果所有代码段的长度都相同,则没有任何优势。对于不同的长度,您的方法可以比模量方法短和长。
丹尼斯

11

打高尔夫球常见的数组和字符串值

有时会出现一些短数组或字符串,例如初始化网格。天真的,这些可能花费4个或更多的字节,因此值得寻找将产生相同结果的内置值操作。特别是基本转换通常很有用。

  • [0 1]可以写成2,
  • [1 0]可以写为YYb(即二进制2)。
  • [1 1]可以写为ZYb(即二进制3)。
  • 矩阵[[0 1] [1 0]]可以写成2e!
  • [LL] 可以写成SS/(用空格分隔一个空格)。
  • "\"\""可以写成L`
  • "{}"可以写成{}s

后者可以扩展到希望所有括号类型都保存另一个字节的情况:

  • "[{<()>}]"可以写成{<()>}a`
  • "()<>[]{}"可以写成{<()>}a`$

特别是对于一些时而突然出现的晦涩的情况,基本转换技巧很有用。例如[3 2]E4b(以4为底的14)。

在更罕见的情况下,您甚至可能会发现分解运算符mf很有用。例如[2 7]Emf

如果您遇到其他任何示例,请随时扩展此列表。


10

清除堆栈

如果您只想清除整个堆栈,请将其包装在数组中并弹出:

];

更为棘手的是,如果您做了很多计算,但只想保留顶部堆栈元素并丢弃下面的所有内容。天真的方法是将顶部元素存储在变量中,清除堆栈,推送变量。但是还有一个更短的选择:将堆栈包装在数组中并提取最后一个元素:

]W=

(感谢Optimizer在前几天向我展示了这一点。)

当然,如果堆栈上只有两个元素,\;则较短。


\;只会弹出TOS下方的元素。你是说;;
CalculatorFeline

1
@CalculatorFeline答案的后半部分是关于清除除TOS之外的所有内容。
Martin Ender

9

e 和十次方

与其他许多语言一样,您可以编写1e3而不是1000使用CJam。

这适用于非整数基数,甚至也适用于非整数指数。例如,1.23e2123.01e.53.162277660168379510的平方根)。

并非立即显而易见的1e3是实际上是两个令牌:

  • 1将整数1压入堆栈。

  • e3将其乘以1000

为什么这么重要?

  • 您可以调用e<numeric literal>已在堆栈中的内容。

    2 3 + e3 e# Pushes 5000.
    
  • 您可以映射e<numeric literal>到数组。

    5 , :e3  e# Pushes [0 1000 2000 3000 4000].
    

9

欧几里得准则

计算向量的欧几里得范数(即其元素的平方和的平方根)的直接方法是:

2f#:+mq

但是,有一种更短的方法。

mh斜边运算符,从堆栈中弹出两个整数ab并压入sqrt(a 2 + b 2

如果我们有一个向量x:= [x 1 …x n ],则堆栈上n> 1:mh(通过斜边减少)将实现以下功能:

  • 首先将x 1x 2压入并mh执行,将sqrt(x 1 2 + x 2 2留在堆栈上。

  • 然后,推入x 3mh再次执行,将
    sqrt(sqrt(x 1 2 + x 2 22 + x 3 2)= sqrt(x 1 2 + x 2 2 + x 3 2留在堆栈上。

  • 处理完x n后,剩下的是sqrt(x 1 2 +…x n 2x的欧几里得范数。

如果n = 1x 1 <0,则上面的代码将产生错误的结果。:mhz无条件工作。(感谢@MartinBüttner指出这一点。)

我在这个答案中第一次使用了这个技巧。


2
当然,这对程序的数值分析有影响...
Peter Taylor

8

从底数为n的数字转换为n

CJam使用以下公式将列表转换为数字:A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0(带非负数n)。n是基数,l是列表长度。这意味着A i可以是任何整数,而不必在的范围内[0,n)

一些例子:

  • 0b提取最后一项并将其转换为整数。像W=i并且保存一个字节(如果不是整数)。但是列表中的所有其他内容也必须能够转换为整数。
  • 1b返回总和。像这样工作:i:+,如果不是整数,则保存两个字节。它也适用于空白列表,而:+不能使用空白列表。
  • [i{_1&9 32?_@\m2/}16*;]W%:c将字符转换为由行尾和制表符组成的字符串,可使用将其转换回2bc。但是,编码功能并不容易在代码高尔夫程序中使用。但是您通常不需要。
  • 您可以使用以下代码将字符串转换为非16位的Unicode字符,可以使用将其转换回2A#b128b:c。(说明将在以后添加。或者稍后再写一个新版本。)

    128b2A#b         " Convert to base 1024. ";
    W%2/)W%\:+       " Convert to two base 1024 digit groups. ";
    [0X@
    {
      _54+
      @I+_Am>@\-
      _Am<@+ 0@-@1^
    }fI
    ]);)
    @\+[~+]2A#b_2G#<!{2A#b}*
    \W%+:c
    

如果您找到某种方法来去除最高有效位数,则类似的方法适用于n具有不同mod值的任何整数集n


8

使用 $用作三元

当您不介意内存泄漏时(即,将未使用的元素留在堆栈中,稍后将使用清除)时];,复制运算符$可以代替三元运算符?

? 如果您设法在推入两个项目之前进行选择来计算条件,则效果很好,但通常情况是条件实际上取决于这些项目,而将其置于它们之上会更加自然。

如果您有A B C堆栈,则可以执行

!$

代替

\@?

复制B是否C属实,并A否则。

如果C是实际的布尔值(01),则可以执行

$

代替

@@?

复制A是否C真实,B否则复制。


事后看来,这是一个相当明显的把戏,但我以前从未想过。我在此答案中第一次使用它。
丹尼斯

7

映射嵌套列表

假设您有一个嵌套列表,例如矩阵:

[[0 1 2][3 4 5][6 7 8]]

或字符串数​​组:

["foo""bar"]

您想将一个块映射到嵌套级别(即,将其应用于每个数字或每个字符)。天真的解决方案是嵌套的%

{{...}%}%

但是,您实际上可以将内部块推入堆栈,然后使用f%f是“带有附加参数的地图”,因此它将%使用块作为第二个参数映射到外部列表:

{...}f%

保存两个字节。

做类似事情的另一个巧妙技巧for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}

5,_f{f{...}}

外部f将映射到第一个范围,并提供第二个范围作为附加参数。但是现在,如果f再次使用,则只有顶部堆栈元素是一个数组,因此您f将内部块映射到该数组,并提供外部“迭代变量”作为附加参数。这意味着内部块与i和一起运行j在堆栈上。

它具有与将一个块映射到一个笛卡尔积上相同的字符数(尽管如果您需要将对作为数组,则后者会变短):

5,_m*{~...}%

不同之处在于,此版本针对所有对产生单一结果数组,而对f生成嵌套列表,如果要将结果存储在网格中(迭代器变量为坐标)列表很有用。

感谢Dennis向我展示了这个技巧。

0.6.4更新

f并且:现在通过雇用包括他们自己在内的任何其他运营商得到了极大的改善。这意味着您现在可以保存更多的字节。现在,将运算符映射到嵌套列表的过程变得更短了:

{:x}%
{x}f%
::x

但是,这实际上对将块映射到嵌套列表没有帮助。

至于将块或算符应用于笛卡尔积,对于块和算符,现在也变得更短了:

5,_f{f{...}}
5,_ff{...}

5,_f{fx}
5,_ffx

很好的是,您现在可以嵌套这些。因此,您可以轻松地将运算符应用于列表的第三级:

:::x

或一些诡计多端的方块:

{...}ff%

伟大的更新。但是仍然没有f~...
jimmy23013

@ user23013 f期望一个二进制运算符,~是一元的;你可能想要:~吗?此外,我们可以在聊天中
aditsu

我是否缺少有关此0.6.4更新的内容?我仍然收到执行这些技巧的错误消息,例如Unhandled char after ':': :link
Runer112

2
@ Runer112为我工作。确保正确重新加载(即,不是从缓存中加载)。根据您的浏览器,Ctrl + F5应该可以工作。
马丁·恩德

@MartinBüttner这确实是由愚蠢的缓存引起的。谢谢。
Runer112

7

ASCII艺术的矢量化运算符

对于许多ASCII艺术挑战,生成两个不同的模式以在以后叠加它们很有用。向量化运算符对实现不同类型的叠加非常有帮助。

运算符向量化的一个有用特性是,对于较短的字符串/数组的每个元素,该运算符仅执行一次,而没有对应字符串/数组的较大元素的元素则保持不变。

  • .e<

    最少的运算符可e<用于成对的字符串,字符,数组和整数。它从堆栈中弹出两个项目,然后将较低的部分推回e。

    由于空格的代码点低于所有其他可打印的ASCII字符,.e<因此可用于“擦除”所生成模式的部分:

    "\/\/\/\/\/" "    " .e<
    
    e# This pushes "    \/\/\/".
    

    有关完整示例,请参阅我对“ 我想要蜂窝”的回答。

  • .e>

    最大运算符e>充当最小运算符,结果相反。

    同样,由于空格的代码点少,.e>可以用来在空格块中插入可打印字符的模式:

    [[" " " " " " " "] [" " " " " " " "]][["+" "" "-" ""]["" "*" "" "/"]] ..e>
    
    e# This pushes [["+" " " "-" " "] [" " "*" " " "/"]].
    

    有关完整示例,请参见我对“ 七个斜杠显示”的回答。

  • .e&

    如果逻辑AND运算符e&是伪造的,则将其左参数推入,否则将其右参数推入。

    如果两个模式都不包含伪造元素,则可以将其有条件地强加于另一个模式:

    "################" " * * * *" .e&
    
    e# This pushes " * * * *########".
    

    有关完整示例,请参阅我对“ 打印美国国旗”的回答

  • .e|

    逻辑OR运算符e|可以按相反的参数顺序使用:

    " * * * *" "################" .e|
    
    e# This pushes " * * * *########".
    

6

使用&检查,如果一个项目是在列表

对于

1 [1 2 3] #W>
1 [1 2 3] #)

您可以使用

1 [1 2 3] &,
1 [1 2 3] &

而是分别返回0/1和true / falsey。


6

z 和非矩形阵列

zip运算符z转置二维1数组A的行和列的元素也可以是可迭代的。

对于非矩形数组–与zipPython中的内置函数(例如,将行截断为相同长度)或Ruby(使用pad nil填充行)不同,CJam只是将数组的列转换为行,而忽略其长度,并且差距。

例如,压缩数组

[
  [1]
  [2 4]
  [3 5 6]
]

相当于压缩数组

[
  [1 4 6]
  [2 5]
  [3]
]

或数组

[
  [1]
  [2 4 6]
  [3 5]
]

随着这三个动作的推进

[
  [1 2 3]
  [4 5]
  [6]
]

在堆栈上。

尽管这z并不是内卷(有时会有用),但它有一些应用。

例如:

  • 我们可以通过两次压缩将数组的列对齐到顶部(即,将第一个数组变成第二个):

    zz
    
  • 对上述方法的较小修改可以用于类似的问题。

    例如,要将数组的列与底部对齐(即,将第二个数组变成第一个数组),我们可以按相反的行顺序压缩两次:

    W%zzW%
    
  • 给定一个字符串数组,我们可以像这样计算最长字符串的长度:

    :,:e>
    

    但是,通过压缩并计算结果的行数,我们可以节省三个字节:

    z,
    

1 如果有任何的“行”的一个不迭代,z将它们视为单身,所以荏苒任意阵列的作品。


1
可视化同一事物的只是一种不同的方式,但是对我来说,如果我z将列转换为行,而跳过空值,则行为将更加合乎逻辑。在此示例中,输入中的第一列为1、2、3,第二列为4、5(跳过空位置),第三列为6。然后是结果的行。
Reto Koradi

@RetoKoradi这是描述它的更好的方法。
丹尼斯

6

例外情况

所有例外在CJam中都是致命的。由于默认情况下忽略输出到STDERR的输出,因此我们可以利用它来发挥优势。

CJam中的所有运算符都通过从堆栈中弹出零个或多个元素,执行某些任务并向堆栈中推入零个或多个元素来工作。执行任务时会发生异常,因此这仍会弹出元素,但不会返回任何内容。

以下是一些用例:

  • 清理一小堆

    要清除包含两个元素的堆栈,@可以使用。@尝试弹出三个堆栈元素,但在弹出第二个元素后失败。

    弹出三个元素的任何其他运算符都将达到相同的目的。

    看到它在这里行动。

  • 从堆栈中删除两个或三个元素

    未针对这些特定元素实现的任何运算符都可以用于在退出之前从堆栈中弹出两个或三个元素。

    要弹出两个元素,b如果其中一个是字符,或者都不是整数,则可以工作。

    要弹出三个元素,t如果最下面的两个元素都不是可迭代的,最下面的可迭代元素为空或都不是整数,则可以工作。

  • 退出循环

    有时,当整数变为零或字符串变得太短时,我们需要退出循环。如果涉及的操作失败零,空字符串或单例,则无需测试这些条件,我们只需让程序顺其自然即可。

    有关涉及算术的示例,请参见此处

    有关涉及字符串的示例,请参见此处

  • 有条件的执行

    如果不应为某些类型的输入执行源代码,则有时我们可以使用使此类输入失败的运算符。

    例如,对于i不为整数ew的字符串将失败,对于长度为0或1的字符串将失败。

    看到它在这里行动。


5

阵列的最大/最小

这是初学者的一个!

当您需要从数组中找到最大或最小数目时,最简单和最小的方法是对数组进行排序,然后取出第一个或最后一个元素。

所以如果数组在变量中 A

A$W=

是最大值,

A$0=

是最小的。

同时获得两个也是可能的

A$)\0=

阅读后,这看起来似乎很明显,但是任何人的第一次尝试都倾向于使用数组e<e>通过数组进行迭代,这就像

A{e<}*

如果要同时使用max和min,则要长2个字节,甚至更长。


当然,如果您不介意剩余的数组剩余部分,则可以实际使用(and )代替0=and W=
马丁·恩德2014年

现在有:e<:e>
aditsu

@aditsu但是,它们并不比上面的提示短。
Optimizer

5

为大量数字使用时间戳记

如果您需要一个非常大但任意的数字,通常可以使用科学记号9e9或将较大的内置变量之一提升为相似的幂,例如KK#。但是,如果您不关心实际数字是多少,并且不必保持一致(例如,作为随机数的上限),则可以使用两个字节

es

代替。这将以毫秒为单位给出当前时间戳,大约为10 12


3
另请注意,如果您想要一个大的任意数字,并且想要一起丢弃一个正数,则可以使用e9
jimmy23013 2014年

5

检查两个字符串/数组不相等

有时,当两个字符串或数组不相等时,您需要一个真值,而在两个字符串或数组不相等时,您需要一个假值。显而易见的解决方案是两个字节:

=!

检查是否相等,然后求逆。但是,在某些情况下,您可以使用

#

#应用于两个数组时,它将实际上搜索第二个数组作为第一个的子数组(并为您提供该子数组开始的索引)。因此,如果两个数组相同,则子数组将在开始时找到并给出0,这是虚假的。但是,如果找不到第二个数组,它将给出-1真实的结果。

我们在两个数组上需要一些附加条件的原因是,如果第二个数组是第一个数组的重要前缀,则这也会产生虚假的值,例如:

"abc""ab"#

给出0尽管字符串不相同。排除这种情况的最简单条件是,如果您知道两个数组的长度相同-在这种情况下,如果一个数组是另一个数组的前缀,则知道它们相等。但是在特定情况下,可能存在较弱的条件也足够了。例如,如果您知道字符串已排序,则前缀将始终是第一个字符串,而不是第二个。


5

c 和16位整数

要使用适当的换行添加(或减去)无符号的16位整数,可以使用+65536%+2G#%

然而,

+ci

短很多。字符在65536处环绕,因此将字符转换为Character(c)然后转换为Long(i)具有与65536%,其附加好处是结果将不会为负。

可以使用相同的技巧来推送65535

Wci

4

电源组

假设您有一个数组,并且想要一个包含该数组所有可能子集的数组。诀窍是从一个空数组开始,然后对于每个元素,复制您已经拥有的子集,然后向其中添加新元素(在没有添加元素的情况保留先前的结果)。请注意,您需要使用基本情况(即仅包含一个空数组的数组)来初始化堆栈:

[1 2 3 4 5]La\{1$f++}/

这样做的好处是,您可以立即在子集上运行一些计算,而无需添加字符。假设您需要所有子集的产品。在这种情况下,基本情况是一个包含以下内容的数组1,并且在每个步骤中,您将获取可能的产品的先前列表,对其进行复制,然后将复制品中的所有内容乘以新元素:

[1 2 3 4 5]1a\{1$f*+}/

4

检查列表中的项目是否全部相同

我认为这也值得一提。采用:

)-

如果不是全部相同,则返回true;如果全部相同,则返回空列表。如果列表为空,则错误。

如果提取的项目本身可能是数组(或字符串):

)a-

使用!!!获取布尔值。如果提取的项目可能是一个数组,并且最多有两种不同的项目,并且您希望将其设为1(如果不是全部相同的话),那么它会更短:

_|,(

4

0= 对于字符串

要检索数组的第一个元素,您必须使用0=(或(,如果您不介意将其余数组留在堆栈上)。

但是,如果该数组是字符串,则强制转换为字符。

"xyz"c e# Pushes 'x.

我不明白为什么CJam不只是c提取任何数组的第一个元素,这将更加有用和一致。
硕果累累

4

将阵列(或堆栈)向左旋转一个单元

CJam具有向左旋转运算符m<,通常应使用该将数组向左旋转任意数量的单位。

某些情况下,您还可以使用(+shift和追加:

[1 2 3]       (+ e# Pushes [2 3 1].
[[1] [2] [3]] (+ e# Pushes [[2] [3] 1].

第二个示例不起作用,因为数组的第一个元素也是可迭代的,因此被+串联而不是附加。

另外,如果您想将旋转后的数组转储到堆栈中,则可以:\无条件使用(通过交换减少):

[1 2 3]       :\ e# Pushes 2 3 1.
[[1] [2] [3]] :\ e# Pushes [2] [3] [1].

只要您没有open [,此技巧还可以用于旋转整个堆栈,即,将最底部的堆栈项移到顶部:

]:\

3

打印列表并清除堆栈

可以说您的堆栈中有一个字符串/数字/等的列表。在上面,下面还有其他一些项目。即

123 "waste" ["a" "b" "rty" "print" "me" "please"]

现在,您只对打印最后一个列表感兴趣,因此您可以

S*]W=

哪个输出

a b rty print me please

当我们使用清除堆栈技巧并仅打印带有空格的列表时,这似乎真的很聪明(有时可能不是打印列表的理想方式)。

这可以打得更远!

p];

短2个字节

如果列表中除了堆栈之外只有1个项目,则它会更短!

p;

的美丽 p是,它从堆栈中删除了最上面的项目,对其进行了字符串化(在末尾还添加了换行符),并立即打印到STDOUT,而无需等待代码完成。

所以上面的代码会输出

["a" "b" "rty" "print" "me" "please"]

这是列表在堆栈中的确切表示!


3

笛卡尔积或两组或更多组的所有可能组合

CJam有一个内置的笛卡尔积计算器m*,该计算器可以计算堆栈中最上面的两个arraylist / strings并从中创建所有可能的对。例如

[1 2 3 4]"abc"m*

树叶

[[1 'a] [1 'b] [1 'c] [2 'a] [2 'b] [2 'c] [3 'a] [3 'b] [3 'c] [4 'a] [4 'b] [4 'c]]

作为堆栈

但是,如果您希望从两个以上的列表/字符串中获取所有可能的组合,该怎么办。您使用m*了多少次?例如

[1 2 3 4][5 6]"abc"m*m*

将以下内容放在堆栈上

[[1 [5 'a]] [1 [5 'b]] [1 [5 'c]] [1 [6 'a]] [1 [6 'b]] [1 [6 'c]] [2 [5 'a]] [2 [5 'b]] [2 [5 'c]] [2 [6 'a]] [2 [6 'b]] [2 [6 'c]] [3 [5 'a]] [3 [5 'b]] [3 [5 'c]] [3 [6 'a]] [3 [6 'b]] [3 [6 'c]] [4 [5 'a]] [4 [5 'b]] [4 [5 'c]] [4 [6 'a]] [4 [6 'b]] [4 [6 'c]]]

请注意,产品仍然是配对,其中一项是配对本身。这是意料之外的,我们希望拼合组合。

有一个简单的方法可以做到这一点。只需将所需的笛卡尔积的每个列表包装在一个数组中,成对创建笛卡尔积并每次对其进行展平:

[1 2 3 4][5 6]"abc"]{m*{(+}%}*

这离开

[['a 5 1] ['b 5 1] ['c 5 1] ['a 6 1] ['b 6 1] ['c 6 1] ['a 5 2] ['b 5 2] ['c 5 2] ['a 6 2] ['b 6 2] ['c 6 2] ['a 5 3] ['b 5 3] ['c 5 3] ['a 6 3] ['b 6 3] ['c 6 3] ['a 5 4] ['b 5 4] ['c 5 4] ['a 6 4] ['b 6 4] ['c 6 4]]

在堆栈上。

想要维持订单吗?,只需交换,然后再将弹出的项目添加回数组即可。即

{m*{(\+}%}*

只想要排列吗?

{m*{(+$}%_&}*

想要组合中仅包含独特元素吗?

{m*{(+_&}%}*

那是所有人。现在


1
现在,您也可以]:m*:e_使用任意数量的数组进行操作
aditsu

3

在字符串上操作

有时,如果您使用复杂的数据结构,而其中的项目很简单,则转换为字符串可能会有所帮助。

例如,如果要获取二维位数组中的前几项或后几项,并且不关心返回的类型,请sA<0=A<或保存一个字节:+A<

或者,如果您想修改输入中的某些位,则可以在评估字符串之前先对其进行修改。

或者,如果您具有此结构并将其转换为简单列表,则:

[[[[[[[[[1]2]3]4]5]6]7]8]9]

您可以通过其他方式对许多字符进行处理:

[a{~)\}h;]W%

但是使用字符串可能会更短:

s:~

即使它的数字可能超过一个数字,它也会更短:

[`La`-~]

要么:

`']-~]

如果不需要另一个包含许多此类数组的数组。


还有e_现在
aditsu

@aditsu查看此答案和评论。有时效果s仍然更好。
jimmy23013 2015年

当然,当您可以直接使用字符串时,它会更短。
aditsu

3

使用N代替La

在许多情况下,您需要初始化为包含空数组作为唯一元素的数组,这La似乎不必要地长了1个字节。

在许多情况下,您还需要在打印之前在每个元素之后添加换行符,这类似于NoN*

但是,如果两者都成立,有时您可能会发现可以使用以下命令初始化数组 N,该将换行符作为唯一元素。确保仅在代码的其余部分中将内容添加到元素的前面,并且首先添加的内容始终是字符或数组。或仅附加一条,如果可以接受一个换行符,这会使它更短。

S如果您需要用空格分隔输出,有时也可以使用。

在极少数情况下,初始元素必须是字符串。但是您仍然可以使用Na比之后添加换行符短的字符串。


2

分裂一个或多个事件

假设您有一个字符串,"abbcdbbfghbdbb"并且想将其分割b

"abbcdbbfghbdbb"'b/

这留在堆栈上:

["a" "" "cd" "" "fgh" "d" "" ""]

注意空字符串吗?那里是因为两个b人在一起,而他们之间什么也没有。有时,您想避免这种情况。你可以这样做

"abbcdbbfghbdbb"'b/La-

或过滤掉空字符串

"abbcdbbfghbdbb"'b/{},

但这是3个额外的字节。

对于此特定用例,鲜为人知的运算符是%。除了进行mod和map以及基于数字("abcd"2%= "ac"%进行拆分外,还可以在字符串/数组上进行拆分。因此,对于上述用例:

"abbcdbbfghbdbb"'b%

会离开

["a" "cd" "fgh" "d"]

在堆栈上。

感谢@ user23013今天在我的答案之一中指出了这一点。


我认为应该将其命名为“也可以学习GolfScript”,该文档中提供了更好的示例。
jimmy23013 2015年

@ user23013,但我们不确定与GS有什么相似之处,而与GS没有相似之处。
Optimizer

2

使用fold / reduce作为infix foreach

我们:x{x}%and和{x}*(或取决于x一元或二进制)的简写。不幸的是,没有等效的infix运算符可以缩短{x}/。但是,通常,当我们这样做时{x}/x实际上是一个二元运算符,它会反复修改位于堆栈下面的项目。如果是这种情况,并且所说的项目不是数组,我们可以通过使用foreach的fold / reduce来节省一个字节:

5 [1 2 3 4]{-}/  e# Gives -5
5 [1 2 3 4]+:-

这是可行的,因为折叠总是使第一个元素保持不变。不幸的是,当修改的元素是数组时,它不会保存字节,因为添加它会解开它。然而,有时您很幸运,您的数组已经在前面包含了该元素,在这种情况下,请记住reduce(而不是{}/在剩余部分上使用之前手动删除该元素)。


2

打印和打印

CJam具有print运算符:o。它可以工作,但是在执行完所有代码后立即打印堆栈。如果在程序末尾清除堆栈,则可以停止它。只需将其结尾:

];

要打印,您可以使用oNop(用作`oNo


3
o和之间的差异更大pp首先将要打印的项目转换为明确的字符串表示形式。p等于执行​`oNo
丹尼斯
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.