Bạn có lời khuyên chung nào cho việc chơi golf trong Mathematica? Tôi đang tìm kiếm những ý tưởng có thể được áp dụng cho các vấn đề về golf nói chung ít nhất là cụ thể đối với Mathematica (ví dụ: "xóa bình luận" không phải là một câu trả lời).
Bạn có lời khuyên chung nào cho việc chơi golf trong Mathematica? Tôi đang tìm kiếm những ý tưởng có thể được áp dụng cho các vấn đề về golf nói chung ít nhất là cụ thể đối với Mathematica (ví dụ: "xóa bình luận" không phải là một câu trả lời).
Câu trả lời:
Các mẹo dưới đây thay đổi từ kinh tế nhất đến thường được sử dụng nhất:
Sử dụng các lệnh cấp cao của Mathematica nếu có thể, thậm chí là các lệnh cồng kềnh:
MorphologicalComponents
: Code-Golf: Quần đảo Count
Khả năng xử lý hình ảnh: ví dụ: Hôm nay (24 tháng 9) là sinh nhật của HONDA
Subsets
IntegerPartitions
Các biện pháp khoảng cách và độ tương tự: ví dụ EuclideanDistance
có thể là một trình tiết kiệm byte. Lưu ý, tuy nhiên, nó thường ngắn hơn để viết Total@Abs[a-b]
thay vì a~ManhattanDistance~b
và Max@Abs[a-b]
thay vì a~ChessboardDistance~b
.
Sử dụng Graphics and
Text
cho nghệ thuật Ascii: ví dụ lập trình Star!
và xây dựng một đồng hồ analog
Biểu tượng chuyên dụng:
logic và thiết lập các ký hiệu hoạt động thay vì tên dạng dài của chúng:, ⋃, ∧,
Map
và Apply
: /@
, //@
. @@
,@@@
Tiền tố và ký hiệu infix:
Print@"hello"
thay cho Print["hello"]
a~f~b
thay cho f[a,b]
Khi một chức năng chỉ được sử dụng một lần, một chức năng thuần túy có thể tiết kiệm một hoặc hai ký tự.
Tham gia chuỗi trong một danh sách. ""<>{"a","b","c"}
thay vìStringJoin@{"a","b","c"}
Khai thác các chức năng có thể liệt kê. Danh sách càng dài càng tốt.
{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}}
Một số hàm dựng sẵn có tên dài có thể được thay thế bằng các biểu thức ngắn hơn.
Ví dụ:
Total
=> Tr
Transpose
=> Thread
hoặc\[Transpose]
True
=> 1<2
False
=> 1>2
Times
=> 1##&
Alternatives
=> $|##&
IntegerQ
=> ⌊#⌋==#&
a[[1]]
=> #&@@a
a[[All,1]]
=> #&@@@a
ConstantArray[a,n]
=> Array[a&,n]
hoặcTable[a,{n}]
Union@a
=> {}⋃a
hoặca⋃a
ToExpression@n
=> FromDigits@n
nếu n
là một sốDivisible[n,m]
=> m∣n
FromDigits[n,2]
=> Fold[#+##&,n]
nếu n
là danh sách 0
s và 1
sComplex@z
=> {1,I}.z
đâu z
là danh sách biểu mẫu{x,y}
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}}]
Fold
mẹo của bạn FromDigits
cũng hoạt động cho bất kỳ cơ sở nào khác ngoại trừ 10
. Ví dụ: FromDigits[n,5]
> Fold[4#+##&,n]
(với phần thưởng là tiết kiệm thêm một byte cho các cơ sở 100
và 1000
).
U+F3C7
.
Echo
là một tùy chọn, vì nó in >>
(và một khoảng trắng) thành STDOUT trước khi in chuỗi thực tế.
Complex[x,y] => {1,I}.{x,y}
, tôi nghĩ x+y*I
là ngắn hơn nhiều với cùng một hiệu ứng?
Đây là một vector khá phổ biến để làm việc với:
{0,0}
Hóa ra điều này có thể được rút ngắn bằng một byte:
0{,}
Thậm chí nhiều byte được lưu nếu vectơ dài hơn hai số không. Điều này cũng có thể được sử dụng để khởi tạo ma trận bằng 0, ví dụ sau đây đưa ra ma trận 2x2 của các số 0:
0{{,},{,}}
Điều này cũng có thể được sử dụng cho các giá trị khác không nếu chúng đủ lớn hoặc đủ nhiều hoặc âm. So sánh các cặp sau:
{100,100}
0{,}+100
{-1,-1}
0{,}-1
{3,3,3,3}
0{,,,}+3
Nhưng hãy nhớ rằng bắt đầu từ 6 giá trị, bạn nên làm tốt hơn 1~Table~6
trong trường hợp này (có khả năng sớm hơn, tùy thuộc vào yêu cầu ưu tiên).
Lý do công việc này là ,
giới thiệu hai đối số vào danh sách, nhưng các đối số bị bỏ qua (bất cứ nơi nào trong Mathicala) đều ẩn Null
. Bên cạnh đó, nhân là Listable
, và 0*x
là 0
đối với hầu như bất kỳ x
(trừ những thứ như Infinity
và Indeterminate
), vì vậy đây là những gì đang xảy ra:
0{,}
= 0*{,}
= 0*{Null,Null}
= {0*Null,0*Null}
= {0,0}
Đối với danh sách 1
s, bạn có thể sử dụng một mẹo tương tự bằng cách sử dụng quy tắc lũy thừa. Có hai cách khác nhau để lưu byte nếu bạn có ít nhất ba 1
giây trong danh sách:
{1,1,1}
1^{,,}
{,,}^0
1^{,,,}
nhỏ hơn một byte 0{,,,}+1
.
{,,}^0
. Tôi sẽ chỉnh sửa bài viết.
Khi chơi mã, bạn sẽ thường sử dụng một cách tiếp cận chức năng, trong đó bạn sử dụng các hàm ẩn danh (thuần túy) với &
cú pháp tốc ký. Có rất nhiều cách khác nhau để truy cập các đối số của hàm như vậy và bạn thường có thể loại bỏ một vài byte bằng cách nắm bắt tốt các khả năng.
Bạn có thể biết điều này nếu bạn đã sử dụng các hàm thuần túy trước đây. Đối số thứ n được gọi là #n
và #
đóng vai trò là bí danh cho #1
. Vì vậy, nếu, giả sử, bạn muốn viết một hàm lấy tham số của hàm khác và đối số của nó (để truyền đối số cho hàm đó), hãy sử dụng
#@#2&
Điều này không hoạt động với các số âm (chẳng hạn như bạn có thể sử dụng khi truy cập danh sách).
Một trong những tính năng ngôn ngữ mới chính trong Mathematica 10 là Association
s, về cơ bản là các bản đồ giá trị khóa với các loại khóa tùy ý, được viết như
<| x -> 1, "abc" -> 2, 5 -> 3 |>
Nếu một liên kết như vậy được truyền vào dưới dạng đối số đầu tiên cho hàm thuần túy, bạn có thể truy cập một số nếu đối số của nó là tham số được đặt tên:
{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)
Lưu ý rằng #
vẫn đề cập đến toàn bộ hiệp hội như mong đợi. Để các tham số được đặt tên hoạt động, các khóa phải là các chuỗi (chẳng hạn, nó sẽ không hoạt động nếu bạn sử dụng các biến không xác định) và các chuỗi đó phải bắt đầu bằng một chữ cái và chỉ chứa các chữ cái và chữ số.
#0
Một tính năng ít được biết đến là nó #0
cũng tồn tại và cung cấp cho bạn chính đối tượng hàm. Điều này có thể thực sự hữu ích trong các quines và quines tổng quát. Trong thực tế, quine Mathicala ngắn nhất (tôi biết) là
ToString[#0][] & []
Điều hơi khó chịu là nó sẽ không cung cấp cho bạn các ký tự chính xác mà bạn đã nhập. Ví dụ, nếu sử dụng @
cho ứng dụng chức năng, nó vẫn sẽ hiển thị [...]
và không gian sẽ được chèn vào một số nơi. Điều này thường sẽ làm cho quine dài hơn một chút so với mong muốn của bạn, nhưng nó sẽ luôn hoạt động, bằng cách đánh golf trước, và sau đó chỉ sao chép đầu ra của nó - mà bây giờ sẽ là một câu hỏi thực sự.
Ngoài quines, điều này cũng có nghĩa là bạn có thể viết mã đệ quy mà không phải đặt tên cho hàm của mình. So sánh ba cách triển khai Fibonacci (ngây thơ nhưng bị đánh gôn) này:
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]]&
Bây giờ đây là nơi ma thuật thực sự bắt đầu. Trình tự không được sử dụng thường xuyên trong việc chơi golf, bởi vì Sequence
nó chỉ là một cái tên quá dài để có giá trị trong hầu hết thời gian. Nhưng trong các chức năng thuần túy là nơi chúng tỏa sáng. Nếu bạn không quen thuộc với các chuỗi, về cơ bản chúng giống như các biểu tượng trong một số ngôn ngữ khác, nếu bạn sử dụng một chuỗi trong List
danh sách đối số của hàm, các phần tử của nó sẽ tự động được mở rộng thành các vị trí riêng biệt. Vì thế
{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]
Bây giờ, trong các hàm thuần túy ##
hoặc ##1
là một chuỗi tất cả các đối số. Tương tự, ##2
là một chuỗi gồm tất cả các đối số bắt đầu từ giây, ##3
tất cả các đối số bắt đầu từ thứ ba, v.v. Vì vậy, để bắt đầu, chúng ta chỉ có thể thực hiện lại Sequence
như là ##&
, tiết kiệm 5 byte. Như một cách sử dụng ví dụ, điều này cung cấp cho chúng ta một giải pháp thay thế cho Join@@list
(xem mẹo này ), không lưu bất kỳ byte nào, nhưng dù sao cũng nên biết về:
##&@@@list
Điều này có hiệu quả làm phẳng cấp độ đầu tiên của một danh sách lồng nhau. Chúng ta có thể làm gì khác với điều này? Đây là một thay thế ngắn hơn 2 byte để RotateLeft
:
RotateLeft@list
{##2,#}&@list
Đối với những điều này một mình nó đáng để giữ tính năng này trong tâm trí. Tuy nhiên, chúng ta có thể làm tốt hơn! Trình tự thực sự thú vị khi xem xét rằng các nhà khai thác thực sự được thực hiện như các chức năng dưới mui xe. Ví dụ a+b
thực sự đánh giá Plus[a,b]
. Vì vậy, nếu chúng ta đưa ra một chuỗi ...
1+##&[1,2,3]
=> Plus[1,##]
=> Plus[1,1,2,3]
=> 7
Thủ thuật này đã được sử dụng trong mẹo này để tiết kiệm một byte Times
, bởi vì juxtap vị trí về mặt kỹ thuật cũng chỉ là một toán tử:
1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6
Bạn cũng có thể sử dụng nó để lưu một byte Unequal
nếu bạn có một giá trị ký tự hoặc biến mà bạn biết không có trong các đối số của mình ( N
có thể sẽ hoạt động trong 99% trường hợp):
Unequal[a,b,c]
N!=##&[a,b,c]
Điều này thậm chí còn thú vị hơn với các toán tử đơn nguyên -
và /
- hai cái sau thực sự được thực hiện theo phương pháp nhân và lũy thừa. Dưới đây là danh sách những điều bạn có thể làm, trong đó cột cuối cùng giả định rằng hàm đã được truyền các đối số 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
Toán tử phổ biến khác là !=
, ==
, &&
, ||
. Những người ít phổ biến cần lưu ý là |
, @*
, /*
. Để kết luận, đây là một mẹo nhỏ tiền thưởng:
#### Times[##,##] Times[a,b,c,a,b,c] (a*b*c)^2
Tiếp tục thử nghiệm với những điều này và cho tôi biết nếu bạn tìm thấy bất kỳ ứng dụng hữu ích hoặc đặc biệt thú vị nào khác!
Sqrt@2
hoặc 2^.5
=>√2
a[[1]]
=>a〚1〛
#+#2&
=>+##&
Flatten@a
=> Join@@a
(đôi khi)
Function[x,x^2]
=> xx^2
hoặc#^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
〚
và 〛
lấy 3 byte mỗi byte (giả sử UTF8)
Lấy cảm hứng từ khám phá gần đây của Dennis cho Julia, tôi nghĩ rằng tôi sẽ xem xét điều này cho Mathematica. Tôi đã biết rằng Mathicala định nghĩa một số lượng lớn các toán tử không sử dụng, nhưng không bao giờ chú ý đến nó.
Để tham khảo, danh sách tất cả các toán tử có thể được tìm thấy ở đây dưới dạng bảng ưu tiên. Hình tam giác trong cột cuối cùng cho biết toán tử đó có nghĩa tích hợp hay không. Mặc dù không phải tất cả những thứ không thể được định nghĩa dễ dàng, nhưng hầu hết chúng có thể.
Thuận tiện, có hai toán tử không được sử dụng với một mật mã nhỏ hơn 256, sao cho chúng có thể được sử dụng dưới dạng các byte đơn trong tệp nguồn được mã hóa ISO 8859-1:
±
(0xB1) có thể được sử dụng làm toán tử tiền tố đơn nguyên hoặc toán tử nhị phân nhị phân.·
(0xB7) có thể được sử dụng như một toán tử infixic hoặc n-ary, cho n> 2.Mặc dù có thêm một nhược điểm: vì một số lý do kỳ lạ khi xác định các toán tử này, bạn cần một khoảng trắng ở phía trước chúng, hoặc nếu không, Mathicala cố gắng phân tích một phép nhân. Khi sử dụng chúng, bạn không cần bất kỳ khoảng trắng nào:
±x_:=2x
x_ ±y_:=x+y
x_ ·y_ ·z_:=x*y+z
Print[±5] (* 10 *)
Print[3±4] (* 7 *)
Print[3·4·5] (* 17 *)
So sánh điều này với:
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 *)
Vì vậy, điều này tiết kiệm một byte khi xác định hàm và hai byte khi sử dụng nó. Lưu ý rằng định nghĩa ·
sẽ không lưu byte cho bốn toán hạng và sẽ bắt đầu tính phí byte cho nhiều toán hạng hơn, nhưng việc sử dụng vẫn có thể lưu byte, tùy thuộc vào các toán tử được sử dụng trong các đối số. Cũng tốt để lưu ý rằng bạn có thể định nghĩa một hàm giá rẻ mà sau đó được gọi là hiệu quả hơn nhiều:
x_ ·y__:={y}
Print[1·2·3·4·5] (* {2, 3, 4, 5} *)
Nhưng lưu ý rằng không thể dễ dàng gọi các hàm biến đổi này bằng một đối số duy nhất. (Bạn có thể làm CenterDot[x]
hoặc ##&[]·x
nhưng nếu bạn thực sự cần điều đó thì rất có thể bạn sẽ tốt hơn với một giải pháp khác.)
Tất nhiên, điều này không tiết kiệm bất cứ điều gì cho các giải pháp khi hàm không được đặt tên đủ, nhưng đôi khi bạn cần xác định các hàm trợ giúp để sử dụng sau này và đôi khi nó ngắn hơn để xác định các hàm được đặt tên, ví dụ như để thiết lập các định nghĩa khác nhau cho các tham số khác nhau. Trong những trường hợp đó, sử dụng toán tử thay vào đó có thể tiết kiệm được một lượng byte kha khá.
Lưu ý rằng việc sử dụng các tệp được mã hóa ISO 8859-1 này yêu cầu $CharacterEncoding
phải được đặt thành giá trị tương thích, như mặc định của Windows WindowsANSI
. Trên một số hệ thống, mặc định UTF-8
này sẽ không thể đọc các điểm mã này từ các byte đơn.
Cách tiếp cận ngây thơ phải lựa chọn giữa y
và z
, tùy thuộc vào việc x
là 0
hay 1
là
If[x<1,y,z]
Tuy nhiên, có một cách ngắn hơn:
y[z][[x]]
Điều này hoạt động vì [[0]]
đưa ra Head
biểu thức, trong trường hợp này y
, trong khi [[1]]
chỉ đưa ra phần tử đầu tiên - trong trường hợp này là đối số đầu tiên , z
.
Bạn thậm chí có thể sử dụng điều này để chọn giữa nhiều hơn hai giá trị:
u[v,w][[x]]
Lưu ý rằng điều này sẽ không hoạt động nếu u
là một chức năng thực sự đánh giá một cái gì đó. Điều quan trọng là Mathicala giữ nguyên u[v,w]
như vậy. Tuy nhiên, điều này hoạt động trong hầu hết các trường hợp, bao gồm nếu u
là một số, một chuỗi hoặc một danh sách.
Tín dụng cho thủ thuật này đi đến alephalpha - tôi đã phát hiện ra điều này trong một trong những câu trả lời của anh ấy.
Nếu x
là dựa trên 1 thay vì dựa trên không, chỉ cần sử dụng
{y,z}[[x]]
hoặc là
{u,v,w}[[x]]
Trong một số trường hợp hiếm hoi, bạn thậm chí có thể sử dụng thực tế là phép nhân không được đánh giá cho một số giá trị:
{"abc","def"}[[x]]
("abc""def")[[x]]
Lưu ý rằng Mathicala thực sự sẽ sắp xếp lại các đối số, của phép nhân nếu nó vẫn chưa được đánh giá, do đó, ở trên giống hệt với
("def""abc")[[x]]
Length
Điều này đã được viết lại hoàn toàn với một số gợi ý từ LegionMammal978 và Misha Lavrov. Rất cám ơn cả hai.
Trong nhiều trường hợp, Length
có thể rút ngắn một chút bằng cách sử dụng Tr
. Ý tưởng cơ bản là biến đầu vào thành một danh sách 1
s, sao cho Tr
tổng hợp chúng sau đó sẽ bằng độ dài của danh sách.
Cách phổ biến nhất để làm điều này là sử dụng 1^x
(cho một danh sách x
). Này hoạt động vì Power
là Listable
và 1^n
đối với hầu hết các giá trị nguyên tử n
được chỉ 1
(bao gồm tất cả các số, chuỗi và biểu tượng). Vì vậy, chúng ta đã có thể lưu một byte với điều này:
Length@x
Tr[1^x]
Tất nhiên, điều này giả định rằng đó x
là một biểu thức có độ ưu tiên cao hơn ^
.
Nếu x
chỉ chứa 0
s và 1
s, chúng ta có thể lưu một byte khác bằng cách sử dụng Factorial
(giả sử x
có độ ưu tiên cao hơn !
):
Length@x
Tr[x!]
Trong một số trường hợp hiếm hoi, x
có thể có độ ưu tiên thấp hơn ^
nhưng vẫn có độ ưu tiên cao hơn phép nhân. Trong trường hợp đó, nó cũng sẽ có mức độ ưu tiên thấp hơn @
, vì vậy chúng tôi thực sự cần phải so sánh với Length[x]
. Một ví dụ về một toán tử như vậy là .
. Trong những trường hợp đó, bạn vẫn có thể lưu một byte với dạng này:
Length[x.y]
Tr[0x.y+1]
Cuối cùng, một số nhận xét về loại danh sách này hoạt động trên:
Như đã đề cập ở trên cùng, điều này hoạt động trên danh sách phẳng chỉ chứa số, chuỗi và ký hiệu. Tuy nhiên, nó cũng sẽ hoạt động trên một số danh sách sâu hơn, mặc dù nó thực sự tính toán một cái gì đó hơi khác. Đối với mảng hình chữ nhật n -D, việc sử dụng Tr
cung cấp cho bạn kích thước ngắn nhất (trái ngược với kích thước đầu tiên). Nếu bạn biết rằng kích thước ngoài cùng là ngắn nhất hoặc bạn biết rằng tất cả chúng đều giống nhau, so với kích thước Tr
vẫn tương đương Length
.
Length@x == Tr[1^x]
. Nên làm việc với hầu hết các danh sách.
Tr[x!]
thay vì Tr[1^x]
để lưu một byte trong trường hợp đặc biệt x
chỉ chứa số không và số không.
Khám phá các giải pháp đệ quy - Mathematica là đa mô hình, nhưng cách tiếp cận chức năng thường là kinh tế nhất. NestWhile
có thể là một giải pháp rất nhỏ gọn để tìm kiếm các vấn đề NestWhileList
và FoldList
rất mạnh mẽ khi bạn cần trả về hoặc xử lý kết quả của các lần lặp trung gian. Map (/@)
, Apply (@@, @@@)
, MapThread
, Và thực sự mọi thứ trên Wolfram của lập trình chức năng trang tài liệu là công cụ mạnh.
Biểu mẫu rút gọn để tăng / giảm - Ví dụ: thay vì While[i<1,*code*;i++]
bạn có thể làmWhile[i++<1,*code*]
Đừng quên bạn có thể tăng / giảm trước - Ví dụ, --i
thay vì i--
. Điều này đôi khi có thể giúp bạn tiết kiệm một vài byte trong mã xung quanh bằng cách loại bỏ một hoạt động chuẩn bị.
Hệ quả với Số 5 của David Carraher: Khi cùng một chức năng được sử dụng nhiều lần, việc gán một biểu tượng cho nó có thể tiết kiệm byte. Ví dụ: nếu bạn đang sử dụng ToExpression
4 lần trong một giải pháp, t=ToExpression
cho phép bạn sử dụng t@*expression*
sau đó. Tuy nhiên, trước khi bạn thực hiện việc này, hãy xem xét liệu ứng dụng lặp lại của cùng chức năng có cho thấy cơ hội cho cách tiếp cận đệ quy kinh tế hơn không.
{}
nếu bạn đang sử dụng @@@
.Trong một số trường hợp, bạn có thể gặp một biểu thức như:
f@@@{{a,b},{c,d}}
Có thể giảm byte bằng cách viết:
f@@@{a|b,c|d}
Alternatives
có độ ưu tiên rất thấp, do đó, nói chung là ổn khi viết biểu thức (một ngoại lệ đáng chú ý là các hàm thuần túy; bạn chỉ có thể sử dụng nó trong phần tử ngoài cùng bên trái Alternatives
).
f@@@{f@a|b~g~1,#^2&@c|d@2}
Lưu ý rằng f@@a|b|c
(thay vì f@@{a,b,c}
) không hoạt động vì Apply
có độ ưu tiên cao hơn Alternative
.
Trong trường hợp này, bạn chỉ cần sử dụng f@@{a,b,c}
.
Hình thức khai thác
Mathematica 10 hỗ trợ cái gọi là "biểu mẫu toán tử", về cơ bản có nghĩa là một số chức năng có thể được sử dụng. Kết hợp một chức năng là tạo ra một chức năng mới bằng cách sửa một trong các toán tử của nó. Giả sử, bạn đang sử dụng SortBy[list, somereallylongfunction&]
rất nhiều list
s khác nhau . Trước đây, bạn có lẽ sẽ được gán SortBy
cho s
và chức năng tinh khiết đến f
vậy
s=SortBy;
f=somereallylongfunction&;
list1~s~f;
list2~s~f;
list3~s~f;
Bây giờ bạn có thể cà ri SortBy
, có nghĩa là bây giờ bạn có thể làm
s=SortBy[somereallylongfunction&];
s@list1;
s@list2;
s@list3;
Các công trình tương tự cho rất nhiều các chức năng khác, trong đó có một danh sách hoặc chức năng lập luận, bao gồm (nhưng không giới hạn) Select
, Map
, Nearest
vv
ybeltukov trên Mathematica.SE đã có thể tạo ra một danh sách đầy đủ về những điều này :
{"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"}
Thành phần và RightCysis
Có các tốc ký mới cho Composition
( @*
) và RightComposition
( /*
). Một ví dụ rõ ràng được đặt ra trong đó những cái này có thể lưu các ký tự được nhìn thấy trong ba dòng tương đương sau
Last@Range@# & /@ Range[5]
Last@*Range /@ Range[5]
Range /* Last /@ Range[5]
Không cần mã như thế này:
f[]:=DoSomething[1,2]
(*...*)
f[]
(*...*)
f[]
Bạn chỉ có thể sử dụng một biến với :=
để đánh giá lại phía bên tay phải:
f:=DoSomething[1,2]
(*...*)
f
(*...*)
f
Điều này cũng có nghĩa là bạn có thể đặt bí danh cho bất kỳ hành động nào mà bạn thực hiện thường xuyên (ngay cả khi đó chỉ là một cái gì đó giống như n++
) với một ký tự với giá 5 byte. Vì vậy, trong trường hợp n++
nó trả lại sau lần sử dụng thứ tư:
n++;n++;n++;n++
f:=n++;f;f;f;f
%
để có được một biến miễn phíMẹo này chỉ có thể áp dụng nếu môi trường REPL của Mathicala có thể được giả định. %
không được xác định khi mã được chạy dưới dạng tập lệnh.
Khi bạn có thể sử dụng các tính năng REPL, đừng làm điều này:
a=someLongExpression;some[other*a,expression@a,using^a]
Thay vào đó, hãy nhớ rằng Mathicala lưu trữ biểu thức được đánh giá cuối cùng (kết thúc dòng mới) trong %
:
someLongExpression;
some[other*%,expression@%,using^%]
Dòng mới được thêm vào có giá một byte, nhưng bạn đang tiết kiệm hai bằng cách loại bỏ a=
, do đó, tổng thể này sẽ tiết kiệm được một byte.
Trong một số trường hợp (ví dụ: khi bạn muốn in giá trị bằng a
mọi cách), bạn thậm chí có thể bỏ qua ;
, lưu hai byte:
someLongExpression
some[other*%,expression@%,using^%]
Một hoặc hai byte có vẻ khá nhỏ, nhưng đây là một trường hợp quan trọng, vì nó làm cho việc trích xuất các biểu thức lặp lại (đây là một kỹ thuật rất phổ biến) hữu ích hơn nhiều khi chơi golf:
Kỹ thuật bình thường để trích xuất các biểu thức lặp đi lặp lại tốn bốn byte chi phí, cần được lưu lại bằng cách sử dụng thêm biểu thức. Dưới đây là một bảng ngắn về số lần sử dụng tối thiểu của một biểu thức (theo độ dài của biểu thức) để trích xuất thành một biến được đặt tên để lưu bất cứ thứ gì:
Length Min. Uses
2 6
3 4
4 3
5 3
6 2
... 2
Bằng cách sử dụng biến không tên, có thể lưu một vài byte thường xuyên hơn:
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
Tôi không nghĩ %%
hoặc %n
có thể được sử dụng để chơi gôn, bởi vì nếu bạn không sử dụng chúng ít nhất hai lần, bạn có thể đặt biểu thức ngay khi cần. Và nếu bạn sử dụng nó hai lần, ký tự bổ sung trong tên biến sẽ hủy bỏ khoản tiết kiệm từ việc bỏ qua một số x=
.
Đây thực chất là một hệ quả tất yếu của mẹo này nhưng đây là một nhiệm vụ đủ phổ biến mà tôi nghĩ rằng nó đảm bảo câu trả lời của chính nó.
Cách ngây thơ để kiểm tra nếu một danh sách theo thứ tự là sử dụng
OrderedQ@a
Chúng ta có thể làm tốt hơn một byte với
Sort@a==a
Tuy nhiên, điều này không hoạt động nếu chúng ta chưa có thứ chúng ta muốn kiểm tra một biến. (Chúng ta cần một cái gì Sort[a=...]==a
đó dài đến mức không cần thiết.) Tuy nhiên, có một lựa chọn khác:
#<=##&@@a
Điều tốt nhất là điều này có thể được sử dụng để kiểm tra xem đầu vào có được sắp xếp ngược lại cho cùng một số byte hay không:
#>=##&@@a
Có thể lưu thêm một byte nếu a) chúng ta biết rằng các thành phần danh sách là khác biệt và b) chúng ta biết giới hạn dưới từ 0 đến 9 (bao gồm; hoặc giới hạn trên cho thứ tự sắp xếp ngược):
0<##&@@a
5>##&@@a
Để xem lý do tại sao điều này hoạt động, hãy xem "Chuỗi các đối số" trong mẹo được liên kết ở trên cùng.
##>0&@@a
. Tương tự cho giới hạn trên để sắp xếp.
Thay vì StringRepeat[str,n]
sử dụng (0Range[n]+str)<>""
. Hoặc nếu str
không phụ thuộc vào bất kỳ đối số vị trí nào, thậm chí tốt hơn là Array[str&,n]<>""
theo mẹo này .
StringRepeat[s,n+1]
sử dụng Array[s&,n]<>s
(ngay cả khi bạn đã có sẵn n+1
một biến).
Table[str,n]<>""
Nếu bạn cần một danh sách các số được sắp xếp ngược lại, không sử dụng
Reverse@Sort@x
nhưng
-Sort@-x
để lưu sáu byte. Sắp xếp theo giá trị âm cũng hữu ích cho các SortBy
tình huống:
Reverse@SortBy[x,Last]
SortBy[x,-Last@#&]
-Sort@-x
?
Bạn có thể dán một biểu thức trong Break
đó có thể lưu một hoặc hai ký tự. Ví dụ ( các chi tiết khác không được đánh golf cho rõ ràng ):
result = False;
Break[]
có thể biến thành
Break[result = False]
để lưu một nhân vật. Nếu biểu thức trong câu hỏi không có độ ưu tiên thấp hơn ứng dụng hàm, bạn thậm chí có thể lưu một ký tự khác:
Print@x;
Break[]
có thể biến thành
Break@Print@x
Mặc dù không có giấy tờ, nhưng đối số Break
dường như được trả về bởi vòng lặp xung quanh, điều này có khả năng dẫn đến tiết kiệm hơn nữa.
Để xóa tất cả khoảng trắng khỏi chuỗi s
, sử dụng
StringSplit@s<>""
Đó là, sử dụng StringSplit
mặc định (chia thành các thành phần không phải khoảng trắng) và chỉ cần nối chúng lại với nhau. Điều tương tự có lẽ vẫn là ngắn nhất nếu bạn muốn loại bỏ bất kỳ ký tự hoặc chuỗi con nào khác:
s~StringSplit~"x"<>""
Range
Một nhiệm vụ rất phổ biến là áp dụng một số loại hàm cho tất cả các số từ 1 đến a n
(thường được đưa ra làm đầu vào). Về cơ bản có 3 cách để làm điều này (sử dụng hàm nhận dạng không tên làm ví dụ):
#&/@Range@n
Array[#&,n]
Table[i,{i,n}]
Tôi có xu hướng đi cho người đầu tiên (vì bất kỳ lý do gì), nhưng điều này hiếm khi là sự lựa chọn tốt nhất.
Array
thay thếVí dụ trên cho thấy việc sử dụng Array
có cùng số byte. Tuy nhiên, nó có lợi thế là nó là một biểu thức duy nhất. Cụ thể, nếu bạn muốn xử lý thêm kết quả bằng một hàm, f
bạn có thể sử dụng ký hiệu tiền tố, giúp lưu một byte qua Range
:
f[#&/@Range@n]
f@Array[#&,n]
Hơn nữa, bạn có thể bỏ qua dấu ngoặc đơn xung quanh hàm không tên mà bạn có thể cần với Range
, ví dụ:
15/(#&)/@Range@n
15/Array[#&,n]
Nếu bạn không muốn sử dụng nó thêm (hoặc với một toán tử có mức độ ưu tiên thấp hơn), thay vào đó bạn có thể Array
tự viết bằng ký hiệu infix và cũng lưu một byte:
#&/@Range@n
#&~Array~n
Do đó, Array
gần như chắc chắn là tốt hơn Range
.
Table
thay thếBây giờ bảng phải chiếm 3 byte hoặc ít nhất là 2 khi ký hiệu infix là một tùy chọn:
#&/@Range@n
i~Table~{i,n}
Khi không sử dụng ký hiệu infix, Table
có thể cho phép bạn bỏ qua dấu ngoặc đơn nếu hàm của bạn bao gồm một số câu lệnh:
(#;#)&/@Range@n
Table[i;i,{i,n}]
Điều này vẫn còn lâu hơn, nhưng cung cấp thêm tiền tiết kiệm trong trường hợp được đề cập dưới đây.
Các khoản tiết kiệm thực sự xuất phát từ thực tế là Table
không nên loại bỏ tên biến đang chạy. Thông thường, bạn sẽ có các hàm không được lồng trong đó bạn muốn sử dụng biến ngoài trong một trong các hàm bên trong. Khi điều đó xảy ra, Table
ngắn hơn Range
:
(i=#;i&[])&/@Range@n
Table[i&[],{i,n}]
i&[]~Table~{i,n}
Bạn không chỉ lưu các ký tự để gán i
, bạn còn có thể giảm hàm thành một câu lệnh trong quy trình, cho phép bạn sử dụng ký hiệu infix trên đầu nó. Để tham khảo, Array
cũng dài hơn trong trường hợp này, nhưng vẫn ngắn hơn Range
:
(i=#;i&[])&~Array~n
Range
?Bất cứ khi nào bạn không cần một hàm gọi để xử lý các giá trị, ví dụ khi ánh xạ có thể được thực hiện thông qua thao tác véc tơ. Ví dụ:
5#&~Array~n
5Range@n
#^2&~Array~n
Range@n^2
Tất nhiên, nó cũng ngắn hơn nếu bạn không muốn ánh xạ bất kỳ chức năng nào, vd
Mean@Array[#&,n]
Mean@Range@n
f/@Range[x]
thường xuyên ...
Một số cấu trúc như thế i=1;While[cond[i],i++]
là tốt, nhưng có một cách thay thế ngắn hơn hai byte:
1//.i_/;cond[i]:>i+1
Đoạn mã trên nhiều lần thay thế một số i
với i+1
khi nó đáp ứng điều kiện cond[i]
. Trong trường hợp này, i
bắt đầu tại 1
.
Lưu ý rằng số lần lặp tối đa mặc định là 2 ^ 16 (= 65536). Nếu bạn cần nhiều lần lặp hơn thế, While
sẽ tốt hơn. ( MaxIterations->∞
quá dài)
Đôi khi bạn có thể thay thế If
bằng một toán tử logic.
Chẳng hạn, giả sử bạn muốn tạo một hàm kiểm tra xem một số có phải là số nguyên tố hay không và in 2*(number) - 1
có đúng không:
If[PrimeQ@#,Print[2#-1]]&
Nó ngắn hơn nếu bạn sử dụng &&
thay thế:
PrimeQ@#&&Print[2#-1]&
Ngay cả khi bạn có nhiều biểu thức, bạn vẫn lưu byte (s):
If[PrimeQ@#,a++;Print[2#-1]]&
PrimeQ@#&&a++&&Print[2#-1]&
(* or *)
PrimeQ@#&&(a++;Print[2#-1])&
Bạn có thể sử dụng ||
cho các trường hợp khi bạn muốn điều kiện là False
:
If[!PrimeQ@#,Print[2#-1]]&
(* or *)
If[PrimeQ@#,,Print[2#-1]]&
(* can become *)
PrimeQ@#||Print[2#-1]&
Những thủ thuật này hoạt động vì các toán tử logic có thể bị ngắn mạch ; đối số thứ hai và sau đó thậm chí không cần phải là biểu thức boolean hợp lệ.
Tất nhiên, điều này không hoạt động nếu bạn cần giá trị trả về If
hoặc khi bạn cần cả hai đối số trung thực và giả dối If
.
Dưới đây là danh sách với vô số các hình thức nhập toán tử có thể rút ngắn rất nhiều thứ. Một số trong số này đã được đề cập trong các bài đăng khác, nhưng danh sách dài và tôi luôn ngạc nhiên khi tìm thấy một vài điều mới trên đó:
Optional (:)
Optional (:)
có thể được sử dụng để mở rộng danh sách trong các thay thế, mà không phải xác định quy tắc riêng cho việc mở rộng.
Câu trả lời này của tôi và câu trả lời này của @ngenisis là ví dụ.
Sử dụng
... /. {p___, a_: 0, b_, q___} /; cond[b] :> ...
Sự thay thế ở trên trước tiên sử dụng mẫu {p___, a_, b_, q___}
và tìm một kết quả khớp với b
một điều kiện nhất định.
Khi không tìm thấy kết quả khớp như vậy, nó sẽ bỏ qua a_
và thay vào đó tìm kiếm {p___, b_, q___}
. a
không được bao gồm trong tìm kiếm và được coi là có giá trị 0
.
Lưu ý rằng tìm kiếm mẫu thứ hai sẽ chỉ hoạt động cho b
điều đó xảy ra ở đầu danh sách; nếu một b
giá trị thỏa mãn một điều kiện ở giữa, thì {p___, a_, b_, q___}
(có độ ưu tiên cao hơn) sẽ khớp với nó.
Sự thay thế tương đương với việc chuẩn bị trước 0
khi b
một điều kiện thỏa mãn xảy ra ở đầu danh sách. (tức là không cần xác định quy tắc riêng, {b_, q___} /; cond[b] :> ...
)
Đối với mã golf, các Function
đối số thuần túy được tham chiếu phổ biến nhất bằng Slot
s; ví dụ #
cho đối số thứ nhất, #2
cho đối số thứ hai, v.v. (xem câu trả lời này để biết thêm chi tiết).
Trong nhiều trường hợp, bạn sẽ muốn làm tổ Function
s. Ví dụ, 1##&@@#&
là một Function
danh sách lấy danh sách làm đối số đầu tiên của nó và đưa ra sản phẩm của các phần tử của nó. Đây là chức năng trong TreeForm
:
Các đối số được chuyển đến cấp cao Function
nhất chỉ có thể điền vào Slot
s và SlotSequence
s ở cấp cao nhất, trong trường hợp này có nghĩa là SlotSequence
bên trong Function
sẽ không có bất kỳ cách nào để truy cập các đối số lên cấp cao nhất Function
.
Tuy nhiên, trong một số trường hợp, bạn có thể muốn một Function
lồng trong một cái khác Function
để có thể tham chiếu các đối số ra bên ngoài Function
. Ví dụ, bạn có thể muốn một cái gì đó như Array[fun,...]&
, trong đó hàm fun
phụ thuộc vào một đối số đến cấp cao nhất Function
. Để cụ thể, hãy nói rằng fun
nên cho phần còn lại của bình phương modulo đầu vào của nó ở mức cao nhất Function
. Một cách để thực hiện điều này là gán đối số cấp cao nhất cho một biến:
(x=#;Array[Mod[#^2,x]&,...])&
Bất cứ nơi nào x
xuất hiện ở bên trong Function
Mod[#^2,x]&
, nó sẽ đề cập đến đối số đầu tiên ở bên ngoài Function
, trong khi đó #
sẽ đề cập đến đối số đầu tiên cho bên trong Function
. Cách tiếp cận tốt hơn là sử dụng thực tế Function
có hai dạng đối số trong đó đối số đầu tiên là ký hiệu hoặc danh sách các ký hiệu sẽ biểu thị các đối số được đặt tên cho Function
(trái ngược với Slot
s không được đặt tên ). Điều này kết thúc việc tiết kiệm cho chúng tôi ba byte trong trường hợp này:
xArray[Mod[#^2,x]&,...]
là ký tự sử dụng riêng ba byte U+F4A1
đại diện cho toán tử infix nhị phân \[Function]
. Bạn cũng có thể sử dụng hình thức nhị phân của Function
bên trong khác Function
:
Array[xMod[x^2,#],...]&
Điều này tương đương với ở trên. Lý do là, nếu bạn đang sử dụng các đối số được đặt tên, thì Slot
s và SlotSequences
được coi là thuộc về bên Function
trên mà không sử dụng các đối số được đặt tên.
Bây giờ chỉ vì chúng ta có thể làm tổ Function
theo cách này, không có nghĩa là chúng ta luôn luôn nên như vậy. Ví dụ: nếu chúng tôi muốn chọn ra các yếu tố của danh sách nhỏ hơn đầu vào, chúng tôi có thể bị cám dỗ làm điều gì đó như sau:
Select[...,xx<#]&
Nó thực sự sẽ ngắn hơn để sử dụng Cases
và tránh sự cần thiết phải lồng Function
hoàn toàn:
Cases[...,x_/;x<#]&
Bạn có thể lưu một byte bằng cách làm việc xung quanh Prepend
hoặc PrependTo
:
l~Prepend~x
{x}~Join~l
{x,##}&@@l
hoặc là
l~PrependTo~x
l={x}~Join~l
l={x,##}&@@l
Thật không may, điều này không giúp ích cho phổ biến hơn Append
, dường như là tương đương ngắn nhất với một Array.push()
ngôn ngữ khác.
BlockMap
là Partition
+Map
Mẹo này cũng có thể có tiêu đề, "Đọc ghi chú phát hành, tất cả chúng". (Để tham khảo, đây là ghi chú phát hành cho 10.2 và ở đây là bản phát hành 10.3 hôm nay .)
Dù sao, ngay cả các bản phát hành nhỏ cũng chứa vô số tính năng mới và một trong những tính năng hữu ích hơn (để chơi gôn) từ 10.2 là BlockMap
chức năng mới . Về cơ bản , nó kết hợp Partition
và Map
, rất phù hợp với người chơi golf, vì Partition
được sử dụng khá thường xuyên và đó là một tên chức năng thực sự khó chịu. Hàm mới sẽ không tự rút ngắn Partition
, nhưng bất cứ khi nào bạn muốn ánh xạ một hàm lên các phân vùng (điều này có thể xảy ra thường xuyên hơn không), giờ đây bạn có thể lưu một hoặc hai byte:
#&/@l~Partition~2
BlockMap[#&,l,2]
#&/@Partition[l,3,1]
BlockMap[#&,l,3,1]
Khoản tiết kiệm thậm chí còn lớn hơn khi vị trí mới của hàm không tên cho phép bạn tự lưu một số dấu ngoặc đơn:
#&@@(#&/@Partition[l,3,1])
#&@@BlockMap[#&,l,3,1]
Thật không may, tôi không biết tại sao họ cũng không thêm vào BlockApply
khi họ ở đó ...
Cũng lưu ý rằng BlockMap
không hỗ trợ tham số thứ 4 mà bạn có thể sử dụng Partition
để có danh sách tuần hoàn:
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... *)
Nếu câu trả lời của bạn kết thúc bằng cách sử dụng cùng một hàm hoặc biểu thức nhiều lần, bạn có thể muốn xem xét việc lưu trữ chúng trong các biến.
Nếu biểu thức của bạn là độ dài l
và bạn sử dụng nó n
lần, nó thường sẽ sử dụng hết l * n
byte.
Tuy nhiên, nếu bạn lưu trữ nó trong biến có độ dài 1, nó sẽ chỉ mất 3 + l + n
byte (hoặc 2 + l + n
byte, nếu bạn chỉ định biến mà bạn sẽ không cần CompoundExpression (;)
hoặc dấu ngoặc đơn).
Ví dụ: chúng ta hãy xem xét một vấn đề đơn giản, tìm các số nguyên tố sinh đôi ít hơn N.
Người ta có thể viết giải pháp 54 byte này:
Select[Range@#,PrimeQ@#&&(PrimeQ[#+2]||PrimeQ[#-2])&]&
Trong ví dụ này, hàm PrimeQ
được sử dụng ba lần.
Bằng cách gán PrimeQ
tên biến, số byte có thể giảm. Cả hai điều sau đây là 48 byte (54 - 6 byte):
Select[p=PrimeQ;Range@#,p@#&&(p[#+2]||p[#-2])&]&
Select[Range@#,(p=PrimeQ)@#&&(p[#+2]||p[#-2])&]&
Sort
thay vìSortBy
Đối với các danh sách như list = {{1, "world"}, {0, "universe"}, {2, "country"}}
, ba tuyên bố sau gần như tương đương.
SortBy[list,#[[1]]&]
list~SortBy~First
Sort@list
Select
vàSortBy
Đôi khi chúng ta cần chọn các mục trong một tập lớn hơn và sắp xếp chúng để tìm mức tối thiểu / tối đa. Trong một số trường hợp , hai hoạt động có thể được kết hợp thành một.
Ví dụ, ở mức tối thiểu, hai câu lệnh sau gần như tương đương nhau.
SortBy[Select[l,SomeFormula==SomeConstant&],SortValue&]
SortBy[l,SortValue+99!(SomeFormula-SomeConstant)^2&]
và
SortBy[Select[l,SomeFormula!=SomeConstant&],SortValue&]
SortBy[l,SortValue+1/(SomeFormula-SomeConstant)&]
1/0
là ComplexInfinity
, "lớn hơn" so với tất cả các số thực.
Đối với danh sách khóa-giá trị, ví dụ:
{SortValue,#}&/@SortBy[Select[l,SomeFormula==SomeConstant],SortValue&]
Sort[{SortValue+99!(SomeFormula-SomeConstant)^2,#})&/@l]
Array
với##&
Khi sử dụng Mảng nhiều chiều để tính toán danh sách các kết quả cần được làm phẳng, hãy sử dụng ##&
làm đối số thứ tư. Điều này thay thế các đầu của Mảng bằng ##&
(tương đương Sequence
) thay vì List
, vì vậy kết quả cuối cùng sẽ là (bằng phẳng) Sequence
kết quả.
Trong hai chiều, so sánh
{Array[f,dims,origin,##&]}
Join@@Array[f,dims,origin]
Tất nhiên,
Join@@Array[f,dims]
vẫn là 2 (hoặc 3, nếu ký hiệu infix có thể được sử dụng) byte ngắn hơn
{Array[f,dims,1,##&]}
.
Trong ba chiều trở lên, {Array[f,dims,origin,##&]}
luôn luôn ngắn hơn so với thay thế, ngay cả khi gốc là 1.
{Array[f,dims,1,##&]}
f~Array~dims~Flatten~2
Các giá trị mặc định xử lý các đối số mẫu bị thiếu một cách hiệu quả. Ví dụ: nếu chúng ta muốn khớp mẫu Exp[c_*x]
theo quy tắc cho bất kỳ giá trị nào c
, thì ngây thơ
Exp[x] + Exp[2x] /. {Exp[c_*x] -> f[c], Exp[x] -> f[1]}
(* f[1] + f[2] *)
sử dụng nhiều byte hơn nếu chúng ta sử dụng giá trị mặc định cho c
bất cứ khi nào nó bị thiếu:
Exp[x] + Exp[2 x] /. Exp[c_.*x] -> f[c]
(* f[1] + f[2] *)
Việc sử dụng mặc định được biểu thị bằng dấu chấm sau mẫu : c_.
.
Các giá trị mặc định được liên kết với các hoạt động: trong ví dụ trên, thao tác nằm Times
trong c_.*x
và c_
do đó , một giá trị bị thiếu được lấy từ giá trị mặc định được liên kết với Times
, đó là 1. Đối với Plus
, giá trị mặc định là 0:
Exp[x] + Exp[x + 2] /. Exp[x + c_.] -> f[c]
(* f[0] + f[2] *)
Đối với Power
số mũ, mặc định là 1:
x + x^2 /. x^n_. -> p[n]
(* p[1] + p[2] *)
(Norm[#-#2]&)
thay vìEuclideanDistance
.