Mathematica打高尔夫球的技巧


41

您在Mathematica打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫问题的想法,这些想法至少在某种程度上特定于Mathematica(例如,“删除评论”不是答案)。

Answers:


30

以下提示从最经济到最常用的不同:

  1. 尽可能使用Mathematica的高级命令,甚至是大命令:

  2. 使用Graphics and Text对ASCII艺术:如星编程!建立一个模拟时钟

  3. 专用符号:

    • 逻辑和设置操作符号,而不是其长格式名称:⋂,⋃,∧,∨

    • MapApply/@//@@@@@@

  4. 前缀和前缀表示法:

    • Print@"hello" 代替 Print["hello"]

    • a~f~b 代替 f[a,b]

  5. 当一个功能仅使用一次时,纯功能可以节省一个或两个字符。

  6. 列表中的连接字符串。""<>{"a","b","c"}代替StringJoin@{"a","b","c"}

  7. 利用可列出的功能。列表越长越好。

    {a, b, c} + {x, y, z}= {a+x, b+y, c+z}

    {2, 3, 4} {5, 6, 7}= {10, 18, 28}

    {{a, b}, {c, d}}^{2, 3} = {{a^2, b^2}, {c^3, d^3}}


2
总是短于写(Norm[#-#2]&)代替EuclideanDistance
user202729

32

某些带有长名称的内置函数可以用较短的表达式替换。

例如:

  • Total => Tr
  • Transpose=> Thread\[Transpose]
  • True => 1<2
  • False => 1>2
  • Times => 1##&
  • Alternatives => $|##&
  • IntegerQ => ⌊#⌋==#&
  • a[[1]] => #&@@a
  • a[[All,1]] => #&@@@a
  • ConstantArray[a,n]=> Array[a&,n]Table[a,{n}]
  • Union@a=> {}⋃aa⋃a
  • ToExpression@n=> FromDigits@n如果n是数字
  • Divisible[n,m] => m∣n
  • FromDigits[n,2]=> Fold[#+##&,n]如果n0s和1s 的列表
  • Complex@z=> {1,I}.z其中z是表单列表{x,y}

5
@belisarius Thread[{{a,b},{c,d}}]== Thread[List[{a,b},{c,d}]]== {List[a,c],List[b,d]}== {{a,c},{b,d}}==Transpose[{{a,b},{c,d}}]
alephalpha 2014年

2
我认为FoldFromDigits除了之外,您的技巧也适用于任何其他基础10。例如FromDigits[n,5]-> Fold[4#+##&,n](额外为base 100和节省了一个字节1000)。
Martin Ender 2015年

1
@ mbomb007 UTF-8中的3个字节。实际上这个字符是U+F3C7
alephalpha

1
我终于安装了10.3。如果我们正在考虑使用完整程序,我不认为这Echo是一个选择,因为它会>>在打印实际字符串之前将(和空格)打印到STDOUT。
马丁·恩德

2
对于Complex[x,y] => {1,I}.{x,y},我认为x+y*I具有相同效果的短得多?
Shieru Asakoto

22

具有重复值的列表

这是一个很常用的向量:

{0,0}

事实证明,可以将其缩短一个字节:

0{,}

如果向量长于两个零,则会保存更多的字节。这也可以用于初始化零矩阵,例如,以下给出零的2x2矩阵:

0{{,},{,}}

如果非零值足够大,足够多或为负,则也可以将其用于非零值。比较以下对:

{100,100}
0{,}+100
{-1,-1}
0{,}-1
{3,3,3,3}
0{,,,}+3

但是请记住,从6个值开始,1~Table~6在这种情况下(最好是更早,具体取决于优先级要求),您最好这样做。

起作用的原因是,在列表中引入了两个参数,但是省略的参数(在Mathematica中的任何地方)都是隐式Nulls。此外,乘法是Listable,并且0*x0几乎所有x(除之类的东西InfinityIndeterminate),所以这里发生了什么:

  0{,}
= 0*{,}
= 0*{Null,Null}
= {0*Null,0*Null}
= {0,0}

对于的列表1,您可以通过使用幂规则来使用类似的技巧。如果1列表中至少有3个,则有两种不同的保存字节的方式:

{1,1,1}
1^{,,}
{,,}^0

7
+1; 这只是表明,尽管Mathematica可能具有所有功能的内置功能,但打高尔夫球可能是一个真正的挑战。
LegionMammal978 '16

如果您想要一个最终以1填充的数组,则该数组1^{,,,}要比少一个字节0{,,,}+1
Misha Lavrov

@MishaLavrov哦,很好。这样可以缩短三个值,也可以使用{,,}^0。我将编辑帖子。
马丁·恩德

19

了解纯函数参数

打高尔夫球的代码时,通常会使用一种功能方法,即使用带有&速记语法的匿名(纯)函数。有很多不同的方法可以访问该函数的参数,并且您可以通过很好地掌握各种可能性来节省几个字节。

访问单个参数

如果您以前使用过纯函数,则可能知道这一点。第n个参数称为#n,并#用作的别名#1。因此,例如,如果您要编写一个将另一个函数及其参数作为参数(将参数传递给该函数)的函数,请使用

#@#2&

这并不会与负数的工作(如访问列表时,您可以使用)。

访问命名参数(V10中的新增功能)

Mathematica 10的主要新语言功能之一是Associations,它基本上是具有任意键类型的键-值映射,写成

<| x -> 1, "abc" -> 2, 5 -> 3 |>

如果将这样的关联作为纯函数的第一个参数传递,则可以访问某些关联(如果其参数作为命名参数):

{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)

请注意,#仍按预期引用整个关联。为了使命名参数起作用,键必须是字符串(例如,如果您使用未定义的变量,则该键将不起作用),并且这些字符串必须以字母开头且仅包含字母和数字。

“自我”论点 #0

还有一个鲜为人知的功能#0,该功能为您提供了功能对象本身。这在quines和广义quines中非常有用。实际上,最短的Mathematica quine(我知道)是

ToString[#0][] & []

有点烦人的是,它不会为您提供您输入的确切字符。例如,如果@用于函数应用程序,它将仍然呈现为,[...]并且在某些地方会插入空格。通常,这会使卷轴比您想要的更长一些,但始终有效,方法是先打高尔夫球,然后复制其输出-现在应该是真正的卷轴。

除了quines外,这还意味着您可以编写递归代码而不必命名函数。比较以下三种(天真但打高尔夫球的)斐波那契实现:

f@0=0;f@1=1;f@n_:=f[n-1]+f[n-2]
f@n_:=If[n<2,n,f[n-1]+f[n-2]]
If[#<2,#,#0[#-1]+#0[#-2]]&

参数序列

现在,这才是真正的魔术开始的地方。打高尔夫球并不经常使用音序,因为Sequence它的名字太长了,在大多数情况下都不值得使用。但是在纯功能中它们才是亮点。如果您不熟悉序列,则它们基本上像其他语言中的splats一样,如果您在List函数的或参数列表中使用序列,则其元素将自动扩展到单独的插槽中。所以

{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]

现在,在纯函数中##或是##1所有参数的序列。同样,##2是从第二个开始的所有参数的序列,##3从第三个开始的所有参数的序列,依此类推。因此,首先,我们可以重新实现Sequence##&,节省5个字节。作为示例用法,这为我们提供了一种替代方法Join@@list(请参阅本技巧部分),该方法不保存任何字节,但是无论如何还是要了解的:

 ##&@@@list

这有效地使嵌套列表的第一层平坦。我们还能做什么呢?这是2字节的替代品RotateLeft

 RotateLeft@list
 {##2,#}&@list

仅就这些而言,值得牢记此功能。但是,我们可以做得更好!当考虑到运算符实际上是作为幕后的函数实现时,序列会变得非常有趣。例如,a+b实际评估为Plus[a,b]。所以,如果我们给一个序列...

1+##&[1,2,3]
=> Plus[1,##] 
=> Plus[1,1,2,3]
=> 7

该技巧已在本技巧中用于上保存一个字节Times,因为并列在技术上也只是一个运算符:

1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6

Unequal如果您有一个单字符值或您不知道参数中不包含的变量,也可以使用它保存一个字节(N可能在99%的情况下有效):

Unequal[a,b,c]
N!=##&[a,b,c]

对于一元运算符,这变得更加有趣,-并且/- 和-后两者实际上是根据乘法和乘幂实现的。这是您可以执行的操作的列表,其中最后一列假定该函数已传递参数a, b, c

Operator    Function                Expanded                    Equivalent to

+##         Plus[##]                Plus[a,b,c]                 a+b+c
1##         Times[1,##]             Times[1,a,b,c]              a*b*c
-##         Times[-1,##]            Times[-1,a,b,c]             -a*b*c
x+##        Plus[x,##]              Plus[x,a,b,c]               x+a+b+c
x-##        Plus[x,Times[-1,##]]    Plus[x,Times[-1,a,b,c]]     x-a*b*c
x##         Times[x,##]             Times[x,a,b,c]              x*a*b*c
x/##        Times[x,Power[##,-1]]   Times[x,Power[a,b,c,-1]]    x*a^b^c^-1
##/x        Times[##,Power[x,-1]]   Times[a,b,c,Power[x,-1]]    a*b*c/x
x^##        Power[x,##]             Power[x,a,b,c]              x^a^b^c
##^x        Power[##,x]             Power[a,b,c,#]              a^b^c^x
x.##        Dot[x,##]               Dot[x,a,b,c]                x.a.b.c

其他常见的运营商!===&&||。不太常见的要记住是|@*/*。总结一下,这是一个小技巧:

####        Times[##,##]            Times[a,b,c,a,b,c]          (a*b*c)^2

继续尝试这些方法,如果您发现其他有用或特别有趣的应用程序,请告诉我!


15

Sqrt@22^.5=>√2

a[[1]]=>a〚1〛

#+#2&=>+##&

Flatten@a=> Join@@a(有时)

Function[x,x^2]=> xx^2#^2&

a〚1;;-1;;2〛=>a〚;;;;2〛

a〚2;;-1 ;;2〛=>a〚2;;;;2〛

a〚All,1〛=>a〚;;,1〛

{{1}}〚1,1〛=>Tr@{{1}}

0&~Array~10=>0Range@10

Range[10^3]=>Range@1*^3


1
请注意,按字节进行测量时,使用和分别占用3个字节(假定为UTF8)
user202729 '18年

12

运算符作为函数

受到丹尼斯最近对朱莉娅的发现的启发,我想我应该对Mathematica进行研究。我知道Mathematica定义了大量未使用的运算符,但从未对其进行过多关注。

作为参考,可以在此处以优先级表的形式找到所有运算符的列表。最后一列中的三角形表示该运算符是否具有内置含义。虽然不是所有的那些都不容易定义,但是大多数都可以。

方便地,有两个未使用的运算符的代码点小于256,因此它们可以在ISO 8859-1编码的源文件中用作单个字节:

  • ± (0xB1)可用作一元前缀运算符或二进制中缀运算符。
  • · (0xB7)可以用作可变参数或n元中缀运算符,其中n> 2。

但是还有另外一个问题:由于一些奇怪的原因,在定义这些运算符时,您需要在它们前面加一个空格,否则Mathematica会尝试解析乘法。使用它们时,您不需要任何空格:

±x_:=2x
x_ ±y_:=x+y
x_ ·y_ ·z_:=x*y+z
Print[±5]  (* 10 *)
Print[3±4] (*  7 *)
Print[3·4·5] (* 17 *)

与以下内容进行比较:

f@x_:=2x
x_~g~y_:=x+y
h[x_,y_,z_]:=x*y+z
Print[f@5]   (* 10 *)
Print[3~g~4] (*  7 *)
Print[h[x,y,z]] (* 17 *)

因此,在定义函数时节省了一个字节,在使用函数时节省了两个字节。请注意,的定义·将不会为四个操作数保存字节,而会为更多操作数开始计算字节,但是用法仍然可以保存字节,具体取决于参数中使用的运算符的优先级。还需要注意的是,您可以廉价地定义一个可变参数函数,然后可以更有效地调用它:

x_ ·y__:={y}
Print[1·2·3·4·5] (* {2, 3, 4, 5} *)

但是请注意,使用单个参数调用这些可变参数函数并不容易。(您可以这样做CenterDot[x]##&[]·x但是如果您确实需要,最好是使用其他解决方案更好。)

当然,对于未命名函数就足够的解决方案,这并没有节省任何东西,但是有时您需要定义辅助函数以供以后使用,有时定义命名函数要短一些,例如为不同的参数设置不同的定义。在那些情况下,使用运算符可以节省大量的字节。

请注意,使用这些ISO 8859-1编码文件需要$CharacterEncoding设置为兼容值,例如Windows default WindowsANSI。在某些系统上,这是默认设置UTF-8,它将无法从单个字节读取这些代码点。


这真的很棒,我不知道Mathematica有运算符列表,甚至没有列出它们的优先级。您确定的那两个运算符肯定会派上用场。
英里

8

根据整数选择值

简易方法之间进行选择y,并z根据是否x0或者1

If[x<1,y,z]

但是,有一种较短的方法:

y[z][[x]]

之所以有效,是因为在这种情况下[[0]]给出了Head表达式的,y[[1]]只是给出了第一个元素-在这种情况下给出了第一个参数z

您甚至可以使用此选项在两个以上的值之间进行选择:

u[v,w][[x]]

请注意,如果它u是一个实际求值的函数,则此方法将不起作用。Mathematica保持u[v,w]原样很重要。但是,这在大多数情况下都有效,包括如果ua是数字,字符串或列表。

这个技巧的功劳归功于alephalpha-我在他的答案之一中发现了这一点。

如果x基于1而不是基于0,则只需使用

{y,z}[[x]]

要么

{u,v,w}[[x]]

在极少数情况下,您甚至可以利用以下事实:对某些值不计算乘法:

{"abc","def"}[[x]]
("abc""def")[[x]]

不过,请注意数学实际上将重新排序的参数,如果它仍然不计算乘法的,所以上面的是相同的,以

("def""abc")[[x]]

8

替代品 Length

LegionMammal978和Misha Lavrov的一些建议已将其完全重写。非常感谢他们俩。

在许多情况下,Length可以使用来缩短一点Tr。基本思想是将输入转换为1s 的列表,以便对其Tr求和,然后等于列表的长度。

最常见的方法是使用1^x(用于list x)。这是有效的,因为Poweris Listable1^n对于大多数原子值而言n,just只是1(包括所有数字,字符串和符号)。这样我们就可以保存一个字节:

Length@x
Tr[1^x]

当然,这是假设该x表达式的优先级高于^

如果x仅包含0s和1s,我们可以使用保存另一个字节Factorial(假设x优先级高于!):

Length@x
Tr[x!]

在极少数情况下,x优先级可能^比乘法低,但优先级仍比乘法高。在这种情况下,它的优先级也将低于@,因此我们确实需要与进行比较Length[x]。这样的运算符的一个示例是.。在这种情况下,您仍然可以使用以下格式保存字节:

Length[x.y]
Tr[0x.y+1]

最后,关于此列表适用于哪种列表的一些说明:

如顶部所述,这适用于仅包含数字,字符串和符号的平面列表。但是,它实际上也可以在一些更深的列表上使用,尽管它实际上计算出的结果略有不同。对于n -D矩形阵列,使用Tr为您提供最短的尺寸(相对于第一个)。如果您知道最外面的维度最短,或者它们都相同,则Tr-expressions仍然等效于Length


3
刚刚找到了更短的解决方案:Length@x == Tr[1^x]。应该适用于大多数列表。
LegionMammal978'2013/

@ LegionMammal978太好了,谢谢:)。我会尽快编辑。
马丁·恩德

1
现在两次,在特殊情况下,我只使用0 Tr[x!]而不是Tr[1^x]保存一个字节,而x只包含零和一。
米莎·拉夫罗夫

@MishaLavrov真的很整洁!:)
Martin Ender's

7
  1. 探索递归解决方案 -Mathematica是多种范例,但是功能性方法通常是最经济的。NestWhile可以是一个非常紧凑的解决方案,以寻找问题,NestWhileListFoldList有强大的,当你需要返回或处理的中间迭代的结果。Map (/@)Apply (@@, @@@)MapThread,真正Wolfram的一切函数式编程文档页面是有效的东西。

  2. 递增/递减的缩写形式 -例如,While[i<1,*code*;i++]您可以代替
    While[i++<1,*code*]

  3. 别忘了您可以预先递增/递减 -例如,--i代替i--。通过消除准备操作,有时可以在周围的代码中节省一些字节。

  4. 大卫·卡拉雷(David Carraher)#5的推论:多次使用同一功能时,为其分配符号可以节省字节。例如,如果您ToExpression在解决方案中使用了4次,则此后t=ToExpression可以使用t@*expression*。但是,在执行此操作之前,请考虑重复使用相同的功能是否表明有机会采用更经济的递归方法。


MapThread经常可以用代替\[Transpose]TIO
user202729

7

{}如果您正在使用,请不要使用@@@

在某些情况下,您可能会遇到类似以下的表达式:

f@@@{{a,b},{c,d}}

通过写以下命令可以减少字节数:

f@@@{a|b,c|d}

Alternatives优先级非常低,因此通常可以编写表达式(一个明显的例外是纯函数;您只能在的最左边的元素中使用它Alternatives)。

f@@@{f@a|b~g~1,#^2&@c|d@2}

请注意,f@@a|b|c(而不是f@@{a,b,c})不起作用,因为Apply它的优先级高于Alternative

在这种情况下,您只需使用即可f@@{a,b,c}


6

仅Mathematica 10

运营商表格

Mathematica 10支持所谓的“运算符形式”,这基本上意味着可以使用某些功能。咖喱函数是通过修复一个运算符来创建一个新函数。假设您使用SortBy[list, somereallylongfunction&]了许多不同list的。之前,你很可能会分配SortBys和纯函数f等等

s=SortBy;
f=somereallylongfunction&;
list1~s~f;
list2~s~f;
list3~s~f;

现在您可以咖喱SortBy,这意味着您现在可以

s=SortBy[somereallylongfunction&];
s@list1;
s@list2;
s@list3;

对于很多其他的功能,采取列表或函数参数,包括(但不限于)同一作品SelectMapNearest,等。

ybeltukov在Mathematica.SE上可以生成以下内容的完整列表

{"AllTrue", "AnyTrue", "Append", "Apply", "AssociationMap", "Cases", 
 "Count", "CountDistinctBy", "CountsBy", "Delete", "DeleteCases", 
 "DeleteDuplicatesBy", "Extract", "FirstCase", "FirstPosition", 
 "FreeQ", "GroupBy", "Insert", "KeyDrop", "KeyExistsQ", "KeyMap", 
 "KeySelect", "KeySortBy", "KeyTake", "Map", "MapAt", "MapIndexed", 
 "MatchQ", "MaximalBy", "MemberQ", "Merge", "MinimalBy", "NoneTrue", 
 "Position", "Prepend", "Replace", "ReplacePart", "Scan", "Select", 
 "SelectFirst", "SortBy", "StringCases"}

组成和权利组成

Composition@*)和RightComposition/*)有新的缩写。在下面的三个等效行中可以看到一个显而易见的示例,其中可以保存字符

Last@Range@# & /@ Range[5]
Last@*Range /@ Range[5]
Range /* Last /@ Range[5]

5

不要写0参数的函数

不需要这样的代码:

f[]:=DoSomething[1,2]
(*...*)
f[]
(*...*)
f[]

您可以简单地使用一个变量with :=来强制重新评估右侧:

f:=DoSomething[1,2]
(*...*)
f
(*...*)
f

这也意味着您可以将经常执行的任何操作(即使只是类似的操作n++)别名为一个字符,而代价是5个字节。因此,如果n++它在第四次使用后还本付息:

n++;n++;n++;n++
f:=n++;f;f;f;f

5

使用%获得自由变量

仅当可以假定Mathematica的REPL环境时,此技巧才适用。 %当代码作为脚本运行时未定义。

当您可以使用REPL功能时,请勿执行以下操作:

a=someLongExpression;some[other*a,expression@a,using^a]

相反,请记住Mathematica将最后计算的(换行符终止的)表达式存储在%

someLongExpression;
some[other*%,expression@%,using^%]

添加的换行符花费一个字节,但是您通过删除a=节省了两个字节,因此总体而言,这节省了一个字节。

在某些情况下(例如,a无论如何要打印值),您甚至;可以省去两个字节:

someLongExpression
some[other*%,expression@%,using^%]

一个或两个字节可能看起来很小,但这是一个重要的情况,因为在打高尔夫球时,提取重复的表达式(这是一种非常普遍的技术)更加有用:

提取重复表达式的常规技术花费了四个字节的开销,这需要通过进一步使用表达式来节省。下表是一个表达式的最小使用次数(按表达式的长度)的简短表(按表达式的长度),以提取到命名变量中以保存任何内容:

Length   Min. Uses
2        6
3        4
4        3
5        3
6        2
...      2

通过使用未命名的变量,可以更频繁地保存几个字节:

When ; is required                        When ; can be omitted

Length   Min. Uses                        Length   Min. Uses
2        5                                2        4
3        3                                3        3
4        3                                4        2
5        2                                ...      2
...      2

我不认为%%%n不能将其用于打高尔夫球,因为如果您至少两次不使用它们,则可以将表达方式放在需要的地方。如果使用两次,变量名中的附加字符会取消一些节省,从而抵消了节省的费用x=


请注意,它在脚本模式下不起作用。
alephalpha

@alephalpha什么是脚本模式?
Martin Ender 2015年


@alephalpha哦,对了,我在那儿闭上了脑袋……所以这意味着它根本无法真正使用,除非可以假设使用REPL环境。
马丁·恩德

5

检查列表是否已排序

这本质上是此技巧的必然结果,但这是一项足够常见的任务,我认为它值得自己回答。

检查列表是否正确的天真的方法是使用

OrderedQ@a

我们可以用

Sort@a==a

但是,如果我们还没有想要检查变量的东西,那么这将不起作用。(我们需要Sort[a=...]==a不必要长的东西。)但是,还有另一种选择:

#<=##&@@a

最好的事情是,这可以用来检查输入是否针对相同的字节数进行了反向排序:

#>=##&@@a

如果a)我们知道列表元素是不同的,并且b)我们知道0到9之间的下限(包括;或反向排序顺序的上限),则可以再保存一个字节:

0<##&@@a
5>##&@@a

要查看其工作原理,请查看顶部链接的技巧中的“参数序列”。


可替代地,(严格)下限为也反向排序工作:##>0&@@a。相似的上限进行排序。
user202729

@ user202729很好,请随时进行编辑(否则,我会在周末尝试这样做)。
Martin Ender

5

重复一个字符串

代替StringRepeat[str,n]使用(0Range[n]+str)<>""。或者,如果str不依赖于任何插槽参数,则Array[str&,n]<>""按照技巧甚至更好。


1
结果:而不是StringRepeat[s,n+1]使用Array[s&,n]<>s(即使您已经有n+1一个变量)。
马丁·恩德

更好,Table[str,n]<>""
attinat

5

如果您需要反向排列的数字列表,请不要使用

Reverse@Sort@x

-Sort@-x

保存六个字节。按负数排序对于以下SortBy情况也很有用:

Reverse@SortBy[x,Last]
SortBy[x,-Last@#&]

2
-Sort@-x
JungHwan Min

1
@JungHwanMin哦,是的,那要好得多。:)
Martin Ender

4

您可以粘贴一个Break可以保存一个或两个字符的表达式。示例(为清晰起见,未详细介绍其他细节):

result = False;
Break[]

可以变成

Break[result = False]

保存一个字符。如果所讨论的表达式的优先级不低于函数应用程序的优先级,则您甚至可以保存另一个字符:

Print@x;
Break[]

可以变成

Break@Print@x

尽管没有记录,但Break周围的循环似乎返回了参数to ,这有可能导致更多的节省。


4

要从字符串中删除所有空格s,请使用

StringSplit@s<>""

也就是说,使用StringSplit的默认设置(拆分为非空白组件),然后将它们重新结合在一起。如果您想摆脱任何其他字符或子字符串,则可能仍然是最短的:

s~StringSplit~"x"<>""

4

替代品 Range

一个非常普通的任务是对从1到a n(通常作为输入)的所有数字应用某种函数。基本上有3种方法可以做到这一点(以未命名的身份函数为例):

#&/@Range@n
Array[#&,n]
Table[i,{i,n}]

我倾向于第一个(无论出于何种原因),但这很少是最佳选择。

使用Array代替

上面的示例显示使用Array具有相同的字节数。但是,它的优点是它是单个表达式。特别是,如果您想使用某个函数进一步处理结果,则f可以使用前缀表示法,这样可以节省一个字节Range

f[#&/@Range@n]
f@Array[#&,n]

此外,您可以省略未命名函数周围的圆括号Range,例如,

15/(#&)/@Range@n
15/Array[#&,n]

如果你希望再使用(或与具有较低优先级的运营商),你可以写,而不是Array自己在中间符号,也节省了字节:

#&/@Range@n
#&~Array~n

因此,Array几乎可以肯定比更好Range

使用Table代替

现在,表必须包含3个字节,如果选择使用infix表示法,则必须至少包含2个字节:

#&/@Range@n
i~Table~{i,n}

使用中缀表示法,Table可能允许省略括号如果你的函数由几个语句:

(#;#)&/@Range@n
Table[i;i,{i,n}]

这仍然更长,但是在下面提到的情况下可以节省更多。

真正的节省源于Table为运行变量指定名称的事实。通常,您会嵌套一些未命名的函数,以便在其中一个内部函数中使用外部变量。发生这种情况时,Table它比短Range

(i=#;i&[])&/@Range@n
Table[i&[],{i,n}]
i&[]~Table~{i,n}

您不仅可以保存用于分配的字符i,还可以在处理过程中将函数简化为单个语句,从而可以在其上使用中缀表示法。供参考,Array在这种情况下也更长,但仍然比Range

(i=#;i&[])&~Array~n

您什么时候真正使用Range

每当您不需要函数调用来处理值时,例如,可以通过向量化操作执行映射时。例如:

5#&~Array~n
5Range@n
#^2&~Array~n
Range@n^2

当然,如果您根本不想映射任何函数,则它也会更短,例如

Mean@Array[#&,n]
Mean@Range@n

最后有人f/@Range[x]经常使用...
LegionMammal978

4

寻找满足条件的最小数

像这样的某种构造i=1;While[cond[i],i++]是可以的,但是还有一个替代方案,即短两个字节:

1//.i_/;cond[i]:>i+1

上面的代码替换重复一些ii+1同时满足条件cond[i]。在这种情况下,i从开始1

请注意,默认最大迭代次数为2 ^ 16(= 65536)。如果您需要更多的迭代,那While会更好。(MaxIterations->∞太长)


4

滥用短路评估

有时您可以If用逻辑运算符代替。

例如,假设您要创建一个函数来检查数字是否为质数,而print 2*(number) - 1是否为真:

If[PrimeQ@#,Print[2#-1]]&

如果使用,它会更短&&

PrimeQ@#&&Print[2#-1]&

即使您有多个表达式,仍然可以保存字节:

If[PrimeQ@#,a++;Print[2#-1]]&

PrimeQ@#&&a++&&Print[2#-1]&
(* or *)
PrimeQ@#&&(a++;Print[2#-1])&

您可以||在希望条件为以下情况时使用False

If[!PrimeQ@#,Print[2#-1]]&
(* or *)
If[PrimeQ@#,,Print[2#-1]]&
(* can become *)
PrimeQ@#||Print[2#-1]&

这些技巧之所以有效,是因为逻辑运算符可能会短路。第二个参数,此后甚至不需要是有效的布尔表达式。

当然,如果您需要返回值If或同时需要的真假参数,则此方法不起作用If



3

使用 Optional (:)

Optional (:) 可用于扩展替换中的列表,而不必为扩展定义单独的规则。

此答案由我这个答案由@ngenisis就是例子。

用法

... /. {p___, a_: 0, b_, q___} /; cond[b] :> ...

上面的替换首先使用该模式{p___, a_, b_, q___}并找到一个b符合特定条件的匹配项。

如果找不到这样的匹配项,它将忽略a_并搜索{p___, b_, q___}a不包含在搜索中,并假定具有值0

请注意,第二个模式搜索仅适用于b列表开头的情况;如果b满足条件的值在中间,则{p___, a_, b_, q___}(优先级更高)将与之匹配。

更换相当于前面加上一个0b满足条件在列表的开始出现。(即,无需定义单独的规则,{b_, q___} /; cond[b] :> ...


3

知道何时(何时不使用)命名的纯函数参数

对于代码高尔夫,纯Function参数通常使用Slots进行引用。例如#,第一个参数,#2第二个参数,等等(有关更多详细信息,请参见此答案)。

在许多情况下,您将需要嵌套Function。例如,1##&@@#&a Function将列表作为第一个参数,并输出其元素的乘积。这是该函数TreeForm

在此处输入图片说明

传递给顶级的参数Function只能填充存在于顶级的Slots和SlotSequences,在这种情况下,这意味着SlotSequence内部的in Function将无法以任何方式访问顶级的参数Function

不过,在某些情况下,您可能希望Function嵌套在另一个嵌套对象中Function,以便能够将参数引用到external Function。例如,您可能想要类似之类的东西Array[fun,...]&,其中函数fun取决于顶层参数Function。为了具体起见,假设fun应该将输入平方的余数取模为顶层Function。实现此目的的一种方法是将顶级参数分配给变量:

(x=#;Array[Mod[#^2,x]&,...])&

x在内部出现的任何地方Function Mod[#^2,x]&,它将指向外部的第一个参数Function,而#将指向内部的第一个参数Function。更好的方法是使用Function具有两个自变量形式的事实,其中第一个自变量是一个符号或符号列表,将表示的已命名自变量Function(与未命名Slots 相对)。在这种情况下,这最终为我们节省了三个字节:

xArray[Mod[#^2,x]&,...]

U+F4A1表示二进制中缀运算符的三字节私人使用字符\[Function]。您还可以Function在另一个内部使用二进制形式Function

Array[xMod[x^2,#],...]&

这等同于以上内容。原因是,如果使用命名参数,则假定Slots和SlotSequences属于Function上面不使用命名参数的next 。

现在仅仅是因为我们可以Function以这种方式嵌套,并不意味着我们总是应该这样做。例如,如果我们想挑选出列表中少于输入的那些元素,我们可能会想做些类似的事情:

Select[...,xx<#]&

实际上,它使用起来会更短,Cases并且不需要Function完全嵌套:

Cases[...,x_/;x<#]&

2

您可以通过周围的工作保存一个字节PrependPrependTo

l~Prepend~x
{x}~Join~l
{x,##}&@@l

要么

l~PrependTo~x
l={x}~Join~l
l={x,##}&@@l

不幸的是,这对于更常见的不利Append,这似乎是Array.push()其他语言中最短的等效语言。


2

Mathematica 10.2:BlockMapPartition+Map

该技巧也可以标题为“阅读发行说明,全部”。(作为参考,这里是10.2今天的10.3版本的发行说明。)

无论如何,即使是次要的发行版也包含许多新功能,而10.2中最有用的功能(对于高尔夫)是新BlockMap功能。它本质上结合了PartitionMap,这对高尔夫球手来说Partition非常有用,因为它被经常使用,并且它是一个非常烦人的函数名称。新函数Partition本身不会缩短,但是只要您想将函数映射到分区上(这可能经常发生),现在就可以保存一两个字节:

#&/@l~Partition~2
BlockMap[#&,l,2]
#&/@Partition[l,3,1]
BlockMap[#&,l,3,1]

当未命名函数的新位置允许您为自己节省一些括号时,节省的费用会更大:

#&@@(#&/@Partition[l,3,1])
#&@@BlockMap[#&,l,3,1]

不幸的是,我不知道为什么BlockApply他们在添加时也没有添加...

还要注意,BlockMap它不支持您可以Partition用来获取循环列表的第四个参数:

Partition[Range@5, 2, 1, 1]
(* Gives {{1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 1}} *)
BlockMap[f, Range@5, 2, 1, 1]
(* Nope... *)

2

将函数和表达式存储在变量中

如果答案最终多次使用相同的函数或表达式,则可能需要考虑将它们存储在变量中。

如果您的表达式是长度,l并且使用了它的n时间,则通常会用完l * n字节。

但是,如果将其存储在length-1变量中,则它将仅占用3 + l + n字节(2 + l + n如果将变量分配到不需要CompoundExpression (;)或放在括号中,则为字节)。


例如,让我们考虑一个简单的问题,找到小于N的双素数

可以写这个54字节的解决方案:

Select[Range@#,PrimeQ@#&&(PrimeQ[#+2]||PrimeQ[#-2])&]&

在此示例中,该函数PrimeQ使用了3次。

通过分配PrimeQ变量名称,可以减少字节数。以下两个都是48字节(54-6字节):

Select[p=PrimeQ;Range@#,p@#&&(p[#+2]||p[#-2])&]&
Select[Range@#,(p=PrimeQ)@#&&(p[#+2]||p[#-2])&]&

2

要获得升序的键值列表,请使用Sort代替SortBy

对于诸如的列表list = {{1, "world"}, {0, "universe"}, {2, "country"}},以下三个语句几乎等效。

SortBy[list,#[[1]]&]
list~SortBy~First
Sort@list

结合SelectSortBy

有时,我们需要从更大的集合中挑选出条目,并对它们进行排序以找到最小值/最大值。在某些情况下,两个操作可以合并为一个。

例如,至少,以下两个语句几乎相等。

SortBy[Select[l,SomeFormula==SomeConstant&],SortValue&]
SortBy[l,SortValue+99!(SomeFormula-SomeConstant)^2&]

SortBy[Select[l,SomeFormula!=SomeConstant&],SortValue&]
SortBy[l,SortValue+1/(SomeFormula-SomeConstant)&]

1/0ComplexInfinity,比所有实数“大”。

对于键值列表,例如:

{SortValue,#}&/@SortBy[Select[l,SomeFormula==SomeConstant],SortValue&]
Sort[{SortValue+99!(SomeFormula-SomeConstant)^2,#})&/@l]

1

扁平化的Array##&

使用多维数组计算需​​要展平的结果列表时,请##&用作第四个参数。这将Array的头替换为##&(等效于Sequence)而不是List,因此最终结果将是结果的(平坦)Sequence结果。

在二维中比较

{Array[f,dims,origin,##&]}
Join@@Array[f,dims,origin]

当然, Join@@Array[f,dims] 仍比短2(或3,如果可以使用中缀表示法)字节 {Array[f,dims,1,##&]}

在三个或更多个维度中,{Array[f,dims,origin,##&]}即使原点为1 ,也总是比替代项短。

{Array[f,dims,1,##&]}
f~Array~dims~Flatten~2

1

默认值

默认值可以有效地处理缺少的模式参数。例如,如果我们想Exp[c_*x]在规则中对任何值进行模式匹配c,那么天真

Exp[x] + Exp[2x] /. {Exp[c_*x] -> f[c], Exp[x] -> f[1]}
(*    f[1] + f[2]    *)

所使用的字节数比c缺少缺省值时要多得多:

Exp[x] + Exp[2 x] /. Exp[c_.*x] -> f[c]
(*    f[1] + f[2]    *)

默认模式的使用在模式后面带有一个点c_.

默认值与操作相关联:在上面的示例中,该操作Times在中c_.*xc_因此从与关联的默认值Times1中获得了的缺失值。对于Plus,默认值为0:

Exp[x] + Exp[x + 2] /. Exp[x + c_.] -> f[c]
(*    f[0] + f[2]    *)

对于Power指数,默认值为1:

x + x^2 /. x^n_. -> p[n]
(*    p[1] + p[2]    *)
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.