在K打高尔夫球的技巧


17

K是Arthur Whitney设计的APL家族中的一种编程语言。虽然官方口译员是开源的,但可以在Kx Systems网站上找到试用版,其工作空间限制为32位寻址空间(这不会对代码高尔夫球造成问题)。捆绑在kdb +数据库中的该版本俗称“ K4”。还提供了开源的K实现,包括基于K3的Kona和我自己的名为oK的解释器,该解释器基于 K5并具有基于浏览器的REPL

Kx Systems有一个包含K4 / kdb + / Q信息的Wiki,而Kona GitHub页面上还有一个优良的收集的参考材料。我已经开始为oK / k5 编写手册,这可能是有用的参考。

J和APL 一样,K是一种非常简洁而强大的语言,通常可以在代码高尔夫球中表现出色。请分享发现的技巧,窍门和成语,如果您还没有尝试过K,那么请考虑尝试一下!请为每个答案发布一个提示!

Answers:


5

叫二元组

假设您有一个二元(2参数)函数f

f: {x+2*y}

通常,您会这样称呼它:

f[3;47]

您可以保存字符,方法是先在第一个参数中使用curry,然后通过并置将生成的部分函数应用于第二个参数:

f[3]47

数组索引自然也适用:

  z: (12 17 98;90 91 92)
(12 17 98
 90 91 92)

  z[1;2]
92

  z[1]2
92

5

打印换行符

如果您的输出必须有换行符,您可能会这样做:

`0:whatever,"\n"

。K2(以及可能的其他版本)具有简洁的功能,您可以在其中打印行列表:

  `0:("abc";"def")
abc
def

因此,如果您需要在输出中添加换行符,请执行以下操作:

`0:,whatever

3

范围

通常,如果您要创建一个有序数的向量,请使用!

  !5
0 1 2 3 4

如果要创建一个以零以外的数字开头的范围,则可以向所得向量添加偏移量:

  10+!5
10 11 12 13 14

有一些不寻常的方法可以在特定情况下更好地工作。例如,如果您的基数和偏移量已经是列表的成员,则可以两次使用“ where”:

  &10 5
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1
  &&10 5
10 11 12 13 14

对于增长较慢的序列,请考虑将“ where”与“ take”结合使用:

  5#2
2 2 2 2 2
  &5#2
0 0 1 1 2 2 3 3 4 4

如果要创建一个倍数范围,可以将的结果相乘,!也可以扫描(\)步长副本的列表:

  2*!5
0 2 4 6 8
  +\5#2
2 4 6 8 10

如果要避免使用括号,则在序列长度可变且步长固定的情况下,前者更好,而在步长变化的情况下,后者更好。选择正确的变体可以保存1或2个字符。一对一的差异也可能对您有利。


2

字符串转换很昂贵。只需使用eval。这个:

0.0$a

可以变成这样:

. a

在K5中,它短了一个字节:

.a

2

每条权利

有时,您可能会发现自己编写(或通过简化得出)通过每个单子应用的带括号的表达式:

  (2#)'3 4 5
(3 3
 4 4
 5 5)

将这种模式转换为应用每种权利的方法要短一个字符:

  2#/:3 4 5
(3 3
 4 4
 5 5)

1

循环排列

二进!在K3 / K4是“旋转”:

  2!"abcd"
"cdab"
  -1!"abcd"
"dabc"

当“ scan”(\)带有一元动词时,它充当定点运算符。在K中,定点运算符反复将其动词应用于某个值,直到重新访问初始值或该值停止更改为止。将旋转与定点扫描相结合提供了一种非常方便的方式来计算列表的一组循环排列:

  ![1]\1 2 4 8
(1 2 4 8
 2 4 8 1
 4 8 1 2
 8 1 2 4)

您可以!通过方括号或括号来创建动词train (1!)

![1]\
(1!)\

(注意 1!\它们的行为完全不同!)它们的长度都是相等的,但是如果旋转步幅不是1,则更希望使用前者。在这种情况下,方括号定为带括号的子表达式“免费”。

例如,这是一个简短的程序,该程序通过蛮力测试字符串x是否包含子字符串y(循环!):

{|/(y~(#y)#)'![1]\x}

K5用户当心!K5改变了dyadic的含义!,因此这项技术并不是那么容易。它将在Kona中按预期工作。


1

避免有条件

K有一个条件构造(:[),它等效于Lisp样式cond

:[cond1;result1; cond2;result2; cond3;result3; default]

您可以根据需要设置任意多个条件,如果没有条件匹配,则返回默认值。

有时(例如在递归程序或以其他方式依赖一系列副作用的程序中),无法使用其中之一来解决问题。但是,在负担得起一些额外工作的情况下,通常可以用列表索引替换“ cond”。

考虑臭名昭著的fizzbuzz程序。以传统的命令式编程风格编写,我们可能会采用:

{:[~x!15;"FizzBuzz";~x!3;"Fizz";~x!5;"Buzz";x]}'1+!100

在除数测试中,这里有很多重复。一种不同的方法认识到有4种情况(一个数,可除数仅3,可除数5,可除数3和5)并尝试直接计算从列表中选择以下一种情况的索引:

{(x;"Fizz";"Buzz";"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

缩短两个字符,并更好地使用该语言。知道列表文字是从右到左求值的,我们还获得了一些其他的高尔夫机会,可以将重用的子表达式组合在一起。在基于cond的版本中,我们很难做到这一点,因为如果不选择字符串大小写,则根本不会评估它们:

{(x;4#t;4_ t;t:"FizzBuzz")@+/1 2*~x!/:3 5}'1+!100

现在,我们总共保存了5个字符。顺便说一句,这个特殊的示例在k5中效果更好,因为我们有“ pack”重载/来处理乘以系数向量和求和的步骤:

{(x;4_t;4#t;t:"FizzBuzz")@2 2/~3 5!\:x}'1+!100

还应注意,“ find”(?)的行为是专门设计用来支持在这种索引中处理“默认”情况的,如果没有找到该项,该行为会在键列表的末尾产生一个索引。考虑以下片段,将元音转换为大写字母:

{("AEIOU",x)"aeiou"?x}'

与以下之一:

{t:"aeiou"?x;:[t<5;"AEIOU"t;x]}'
{:[~4<t:"aeiou"?x;"AEIOU"t;x]}'

(我知道我也想阅读!)

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.