Mathematica'da golf oynamak için hangi genel ipuçlarınız var? Genel olarak golf problemlerini kodlamak için uygulanabilecek fikirleri arıyorum, en azından biraz Mathematica'ya özgüdür (örneğin, "yorumları kaldır" bir cevap değildir).
Mathematica'da golf oynamak için hangi genel ipuçlarınız var? Genel olarak golf problemlerini kodlamak için uygulanabilecek fikirleri arıyorum, en azından biraz Mathematica'ya özgüdür (örneğin, "yorumları kaldır" bir cevap değildir).
Yanıtlar:
Aşağıdaki ipuçları en ekonomikten en sık kullanılana kadar değişebilir:
Mathematica'nın yüksek düzeyli komutlarını mümkün olduğunda, hatta büyük olanları kullanın:
MorphologicalComponents
: Kod Golf: Adalar Say
Görüntü işleme yetenekleri: örn. Bugün (24 Eylül) HONDA'nın doğum günü
Subsets
IntegerPartitions
Uzaklık ve Benzerlik ölçüleri: örneğin EuclideanDistance
bir bayt koruyucu olabilir. Bununla birlikte, bunun Total@Abs[a-b]
yerine a~ManhattanDistance~b
ve Max@Abs[a-b]
yerine yazmanın genellikle daha kısa olduğunu unutmayın a~ChessboardDistance~b
.
Graphics and
Text
Ascii sanatı için kullanın : örn. Yıldız programlama! Analog saat oluşturma
ve oluşturma
Özel semboller:
mantık ve uzun form adları yerine işlem sembollerini ayarlayın: ⋂, ⋃, ∧, ∨
Map
ve Apply
: /@
, //@
. @@
,@@@
Önek ve infix notasyonu:
Print@"hello"
yerine Print["hello"]
a~f~b
yerine f[a,b]
Bir fonksiyon yalnızca bir kez kullanıldığında, saf bir fonksiyon bir veya iki karakteri ekonomik hale getirebilir.
Bir listede dizeleri birleştirmek. ""<>{"a","b","c"}
onun yerineStringJoin@{"a","b","c"}
Listable fonksiyonlarını kullan. Listeler ne kadar uzun olursa o kadar iyidir.
{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}}
Uzun adlara sahip bazı yerleşik işlevler daha kısa ifadelerle değiştirilebilir.
Örneğin:
Total
=> Tr
Transpose
=> Thread
veya\[Transpose]
True
=> 1<2
False
=> 1>2
Times
=> 1##&
Alternatives
=> $|##&
IntegerQ
=> ⌊#⌋==#&
a[[1]]
=> #&@@a
a[[All,1]]
=> #&@@@a
ConstantArray[a,n]
=> Array[a&,n]
veyaTable[a,{n}]
Union@a
=> {}⋃a
veyaa⋃a
ToExpression@n
=> FromDigits@n
Eğer n
bir sayıdırDivisible[n,m]
=> m∣n
FromDigits[n,2]
=> Fold[#+##&,n]
eğer s ve s n
listesi ise0
1
Complex@z
=> Şeklinde bir listesi{1,I}.z
z
{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
numarasının FromDigits
dışında başka bir üs için de işe yarar 10
. Örneğin FromDigits[n,5]
-> Fold[4#+##&,n]
(üsler için ekstra bir bayt kaydetme bonusu ile 100
ve 1000
).
U+F3C7
.
Echo
, bir seçenek olduğunu sanmıyorum çünkü >>
asıl diziyi yazdırmadan önce STDOUT'a yazdırıyor (ve bir boşluk).
Complex[x,y] => {1,I}.{x,y}
, x+y*I
aynı etkiyle çok daha kısa olduğunu düşünüyorum ?
Bu, çalışmak için oldukça yaygın bir vektördür:
{0,0}
Bunun bir bayt tarafından kısaltılabileceği ortaya çıktı:
0{,}
Vektör iki sıfırdan uzunsa daha da fazla bayt kaydedilir. Bu, sıfır matrisleri başlatmak için de kullanılabilir, örneğin aşağıdakiler 2x2 sıfır matris verir:
0{{,},{,}}
Bu, eğer yeterince büyük veya yeterince çok veya negatifse sıfır olmayan değerler için de kullanılabilir. Aşağıdaki çiftleri karşılaştırın:
{100,100}
0{,}+100
{-1,-1}
0{,}-1
{3,3,3,3}
0{,,,}+3
Ancak, 6 değerden başlamanın 1~Table~6
bu durumda daha iyi durumda olduğunuzu unutmayın (öncelik şartlarına bağlı olarak potansiyel olarak daha erken).
Bu eserler nedeni olmasıdır ,
(her yerde Mathematica) tanıtır iki listeye argümanlar, ancak ihmal argümanlar örtülü olan Null
ın. Dahası, çarpma Listable
ve neredeyse her 0*x
şey 0
için x
( Infinity
ve gibi şeyler hariç Indeterminate
), işte burada olanlar:
0{,}
= 0*{,}
= 0*{Null,Null}
= {0*Null,0*Null}
= {0,0}
1
S listeleri için, üs kurallarını kullanarak benzer bir numara kullanabilirsiniz. 1
Listede en az üç saniyeniz varsa, baytları kaydetmenin iki farklı yolu vardır :
{1,1,1}
1^{,,}
{,,}^0
1^{,,,}
zaman bir bayt daha küçüktür 0{,,,}+1
.
{,,}^0
. Gönderiyi düzenlerim.
Golf kodunu yazarken, genellikle &
steno sözdiziminde adsız (saf) işlevler kullandığınız bir işlevsel yaklaşım kullanırsınız . Böyle bir işlevin argümanlarına erişmenin birçok farklı yolu vardır ve olasılıkları iyi bir şekilde kavrayarak bir kaç baytı tıraş edebilirsiniz.
Daha önce saf işlevler kullandıysanız, muhtemelen bunu biliyorsunuzdur. N inci bağımsız değişken olarak adlandırılır #n
ve #
bir takma ad olarak hareket eder #1
. Yani, parametre olarak başka bir işlev ve argümanını alan bir işlev yazmak istiyorsanız (argümanı bu işleve iletmek için),
#@#2&
Bu mu değil negatif sayılar ile çalışmak (örneğin listeleri erişirken kullanabileceği gibi).
Mathematica 10'daki yeni ana dil özelliklerinden biri Association
, temelde rasgele anahtar türleriyle anahtar-değer haritaları olan ve
<| x -> 1, "abc" -> 2, 5 -> 3 |>
Eğer böyle bir ilişkilendirme saf bir işlevin ilk argümanı olarak geçerse, bazı argümanlara isimlendirilmiş parametreler olarak erişebilirsiniz:
{#, #2, #3, #abc, #xyz} & [<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th"]
(* {<| "abc" -> "1st", "xyz" -> "2nd", abc -> "3rd" |>, "4th", "5th", "1st", "2nd"} *)
Not #
, beklendiği gibi yine de tüm olarak birleştirilmesi anlamına gelir. İşe adlandırılmış parametreler için, anahtarlar olmak zorunda dizeleri (o mısın mesela tanımsız değişkenleri kullanın değilse iş) ve bu dizeleri bir harfle başlar ve sadece harf ve rakam içermelidir.
#0
Daha az bilinen bir özellik #0
de var olması ve size fonksiyon nesnesinin kendisini vermesidir. Bu, çok sayıda ve genelleştirilmiş sicimlerde gerçekten faydalı olabilir. Aslında, en kısa Mathematica quine (biliyorum)
ToString[#0][] & []
Biraz can sıkıcı olan, girdiğiniz karakterleri size tam olarak vermeyeceğidir. Örneğin, eğer @
işlev uygulaması için kullanılırsa, yine [...]
aynı şekilde işleyecektir ve bazı yerlerde boşluklar eklenecektir. Bu genellikle quine olmasını istediğinizden biraz daha uzun hale getirir, ancak her zaman işe yarar, önce quine golf ederek ve sonra sadece çıktılarını kopyalayarak - ki şimdi gerçek bir quine olması gerekir.
Bu, sorguların dışında, fonksiyonunuzu adlandırmanıza gerek kalmadan özyinelemeli kodlar yazabileceğiniz anlamına gelir. Bu üç (saf ancak golf) Fibonacci uygulamalarını karşılaştırın:
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]]&
İşte gerçek sihrin başladığı yer burası. Sıralamalar golf oynamakta pek kullanılmaz, çünkü Sequence
çoğu zaman buna değmeyecek kadar uzun bir isimdir. Fakat saf fonksiyonlarda parladıkları yer burasıdır. Dizilere aşina değilseniz, temel olarak bazı dillerdeki uyarılar gibidir List
, bir işlev dizisini veya bir işlev dizisini kullanırsanız , öğeler otomatik olarak ayrı yuvalara genişletilir. Yani
{1, Sequence[2, 3, 4], 5} == {1, 2, 3, 4, 5}
f["a", Sequence[0, {}], "b"] == f["a", 0, {}, "b"]
Şimdi, saf işlevlerde ##
veya ##1
tüm argümanların bir dizisidir. Aynı şekilde, ##2
ikinciden başlayarak tüm argümanların bir dizisi ##3
, üçüncü argümandan başlayarak tüm argümanlar, yani bir başlangıç için, sadece 5 bayt tasarrufu Sequence
olarak yeniden uygulayabiliriz ##&
. Örnek bir kullanım olarak, bu bize herhangi bir bayt kaydetmeyen fakat yine de bilmek iyi olan Join@@list
( bu ipucuna bakınız ) alternatifini sunar :
##&@@@list
Bu, iç içe geçmiş bir listenin ilk düzeyini etkin biçimde düzleştirir. Bununla başka ne yapabiliriz? İşte 2 bayt daha kısa bir alternatif RotateLeft
:
RotateLeft@list
{##2,#}&@list
Yalnız bunlar için bu özelliği akılda tutmaya değer. Ancak daha iyisini yapabiliriz! Operatörler aslında kaputun altındaki işlevler olarak uygulandığında, diziler gerçekten ilginçleşiyor. Örneğin, a+b
aslında değerlendirir Plus[a,b]
. Öyleyse bir dizi verirsek ...
1+##&[1,2,3]
=> Plus[1,##]
=> Plus[1,1,2,3]
=> 7
Bu hile, bu ipucunda bir bayttan tasarruf etmek için kullanılmıştır Times
, çünkü yan yana yerleştirme teknik olarak aynı zamanda bir operatördür:
1##&[1,2,3]
=> Times[1,##]
=> Times[1,1,2,3]
=> 6
Unequal
Argümanlarınızda olmadığını bildiğiniz tek karakterli bir değeriniz veya değişkeniniz varsa bunu bir bayttan tasarruf etmek için de kullanabilirsiniz ( N
muhtemelen vakaların% 99'unda işe yarar ):
Unequal[a,b,c]
N!=##&[a,b,c]
Bu, unary operatörleri ile daha da ilginçleşir -
ve /
sonuncusu aslında çarpma ve üstelleştirme anlamında uygulanır. Son sütunun, işlevin argümanları ilettiğini varsaydığı, yapabileceğiniz şeylerin bir listesi 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
Diğer sık operatörleri !=
, ==
, &&
, ||
. Akılda tutulması gereken az yaygın olanlardır |
, @*
, /*
. Sonuç olarak, burada küçük bir bonus numarası:
#### Times[##,##] Times[a,b,c,a,b,c] (a*b*c)^2
Bunları denemeye devam edin ve başka yararlı veya özellikle ilginç uygulamalar bulursanız bana bildirin!
Sqrt@2
veya 2^.5
=>√2
a[[1]]
=>a〚1〛
#+#2&
=>+##&
Flatten@a
=> Join@@a
(bazen)
Function[x,x^2]
=> xx^2
veya#^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
〚
ve 〛
alır 3 her biri (UTF8'i varsayalım) bayt
Dennis'in son Julia'yı keşfetmesinden esinlenerek bunu Mathematica'da araştıracağımı düşündüm. Mathematica'nın çok sayıda kullanılmayan işletmeci tanımladığını, ancak buna hiç dikkat etmediğini biliyordum.
Başvuru için, tüm operatörlerin listesi burada bir öncelik tablosu şeklinde bulunabilir . Son sütundaki üçgen, operatörün yerleşik bir anlamı olup olmadığını gösterir. Kolayca tanımlanamayanların hepsi kolay olmasa da, çoğu yapabilir.
Elverişli bir şekilde, ISO 8859-1 kodlanmış bir kaynak dosyasında tek bayt olarak kullanılabilecekleri, kod noktası 25'ten küçük olmayan kullanılmayan iki operatör vardır:
±
(0xB1), unary önek operatörü veya ikili infix operatörü olarak kullanılabilir.·
(0xB7), n> 2 için değişken ya da n ary infix operatörü olarak kullanılabilir.Yine de bir tane daha yakalamak var: Bu operatörleri tanımlarken garip bir nedenden ötürü , önünde bir alana ihtiyacınız var, ya da Mathematica bir çarpımı ayrıştırmaya çalışıyor. Bunları kullanırken olsa da herhangi bir boşluk gerekmez:
±x_:=2x
x_ ±y_:=x+y
x_ ·y_ ·z_:=x*y+z
Print[±5] (* 10 *)
Print[3±4] (* 7 *)
Print[3·4·5] (* 17 *)
Şununla karşılaştır:
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 *)
Böylece, işlev tanımlanırken bir bayt, kullanırken ise iki bayt tasarruf edilir. Un tanımının ·
dört işlenen için bayt kaydetmeyeceğini ve daha fazla işlenen için maliyet bayt olarak başlayacağını unutmayın; ancak kullanım, bağımsız değişkenlerde kullanılan işleçlerin önceliğine bağlı olarak, bayt tasarrufuna neden olabilir. Ayrıca daha sonra daha verimli olarak adlandırılabilecek değişken bir işlevi ucuza tanımlayabileceğinizi de not etmek iyi:
x_ ·y__:={y}
Print[1·2·3·4·5] (* {2, 3, 4, 5} *)
Ancak bu değişken işlevlerini tek bir argümanla çağırmanın kolay olmadığını unutmayın. (Yapabilirsin CenterDot[x]
ya da ##&[]·x
gerçekten ihtiyacın olursa iyi bir şansın varsa, farklı bir çözümle daha iyi olursun.)
Tabii ki, bu isimlendirilmemiş bir fonksiyonun yeterli olduğu çözümler için hiçbir şey kaydetmiyor, fakat bazen daha sonra kullanılmak üzere yardımcı fonksiyonları tanımlamanız gerekmekte ve örneğin adlandırılmış fonksiyonları tanımlamak, örneğin farklı parametreler için farklı tanımlamalar yapmak daha kısa olmaktadır. Bu gibi durumlarda, bir işleç kullanmak, uygun miktarda bayt tasarrufu sağlayabilir.
Bu ISO 8859-1 kodlu dosyaların kullanılmasının $CharacterEncoding
Windows varsayılanı gibi uyumlu bir değere ayarlanması gerektiğini unutmayın WindowsANSI
. Bazı sistemlerde bu varsayılanlar UTF-8
bu kod noktalarını tek bayttan okuyamaz.
Naif yaklaşım arasında seçim yapmak y
ve z
bağlı olarak x
ise 0
veya 1
bir
If[x<1,y,z]
Ancak, daha kısa bir yol var:
y[z][[x]]
Bunun nedeni eserler [[0]]
veren Head
bu durumda, bir ifadenin y
, oysa [[1]]
sadece birinci elemanı verir - bu durumda ilk argüman, z
.
İkiden fazla değer arasında seçim yapmak için bunu bile kullanabilirsiniz:
u[v,w][[x]]
u
Bunun aslında bir şeyi değerlendiren bir işlev olması durumunda bunun işe yaramayacağını unutmayın . Mathematica'nın u[v,w]
olduğu gibi kalması önemlidir . Ancak bu, eğer u
bir sayı, bir dize veya bir liste de dahil olmak üzere çoğu durumda çalışır .
Bu numara için verilen krediler alfa'ya gidiyor - Bunu cevabından birinde keşfettim.
Eğer x
sıfır tabanlı, sadece kullanım yerine 1 tabanlı
{y,z}[[x]]
veya
{u,v,w}[[x]]
Bazı nadir durumlarda, çarpımın bazı değerler için değerlendirilmediğinden bile yararlanabilirsiniz:
{"abc","def"}[[x]]
("abc""def")[[x]]
Her ne kadar Mathematica'nın gerçekte argümanları, çarpma işleminin argümanlarını yeniden sıralayacağını, ancak yukarıdakilerin aynı olduğunu unutmayın.
("def""abc")[[x]]
Length
Bu tamamen LegionMammal978 ve Misha Lavrov'un bazı önerileri ile yeniden yazılmıştır. İkisine de çok teşekkürler.
Çoğu durumda, Length
faydalanarak biraz kısaltılabilir Tr
. Temel fikir, girişi bir 1
s listesine dönüştürmek , böylece Tr
listenin uzunluğuna eşit olacak şekilde onları özetlemektir.
Bunu yapmanın en yaygın yolu kullanmaktır. 1^x
(bir liste için x
). Bunun nedeni çalışır Power
olduğunu Listable
ve 1^n
çoğu atom değerler için n
sadece bir 1
(tüm sayılar, dizeler ve semboller dahil). Böylece bir bayt'ı bununla kurtarabiliriz:
Length@x
Tr[1^x]
Elbette, bu x
, öncekinden daha yüksek bir ifade olduğunu varsayar ^
.
Eğer x
sadece içerir 0
s ve 1
s, biz kullanarak başka byte kaydedebilirsiniz Factorial
(varsayarak x
daha yüksek önceliğe sahiptir !
):
Length@x
Tr[x!]
Bazı nadir durumlarda, x
^
çarpmalardan daha düşük önceliğe, ama yine de yüksek önceliğe sahip olabilir. Bu durumda aynı zamanda daha düşük önceliğe sahip olacak @
, bu yüzden gerçekten karşılaştırmamız gerekiyor Length[x]
. Böyle bir işlecin bir örneği .
. Bu durumlarda, hala bu form ile bir bayt kaydedebilirsiniz:
Length[x.y]
Tr[0x.y+1]
Son olarak, bunun ne tür listeler üzerinde çalıştığı hakkında bazı açıklamalar:
Yukarıda da belirtildiği gibi, bu sadece sayıları, karakterleri ve simgeleri içeren düz listelerde çalışır. Ancak, aslında biraz daha farklı bir şey hesaplasa da, daha derin listelerde çalışacaktır. Bir n- D dikdörtgen dizisi için, kullanmak Tr
size en kısa boyutu verir (ilkine göre). En dıştaki boyutun en kısa olduğunu biliyorsanız, ya da hepsinin aynı olduğunu biliyorsanız, Tr
ifadeler hala eşdeğerdirLength
.
Length@x == Tr[1^x]
. Çoğu liste ile çalışmalı.
Tr[x!]
yerine kendimi kullanırken buldum . Tr[1^x]
x
Özyinelemeli çözümleri keşfedin - Mathematica çok paradigmadır, ancak işlevsel yaklaşım genellikle en ekonomik olanıdır. NestWhile
arama sorunlara oldukça kompakt bir çözüm olabilir ve NestWhileList
ve FoldList
iade veya ara tekrarlamalar sonuçlarını işlemek için gerektiğinde güçlüdür. Map (/@)
, Apply (@@, @@@)
ve MapThread
, gerçekten de Wolfram'ın İşlevsel Programlaması hakkında her şey dokümantasyon sayfasından güçlü şeyler.
Artırma / azaltma için kısaltılmış form - Örneğin, While[i<1,*code*;i++]
siz yerineWhile[i++<1,*code*]
Unutma, arttırma / azaltma yapabilirsin - Örneğin,--i
yerine i--
. Bu, hazırlık işlemlerini ortadan kaldırarak bazen çevre kodunda birkaç bayttan tasarruf etmenizi sağlayabilir.
Sonuç olarak David Carraher'ın # 5'i: Aynı fonksiyon birçok kez kullanıldığında, ona bir sembol atamak baytları kurtarabilir. Örneğin, ToExpression
bir çözeltide 4 kez kullanıyorsanız , daha sonra t=ToExpression
kullanmanızı sağlar t@*expression*
. Ancak, bunu yapmadan önce aynı işlevin tekrarlanan uygulamasının daha ekonomik bir özyinelemeli yaklaşım için bir fırsat gösterip göstermediğini göz önünde bulundurun.
{}
kullandığınız takdirde @@@
.Bazı durumlarda, şöyle bir ifadeyle karşılaşabilirsiniz:
f@@@{{a,b},{c,d}}
Yazarak bayt azaltmak mümkündür:
f@@@{a|b,c|d}
Alternatives
çok düşük önceliğe sahip olduğundan, ifadeler yazmak genellikle tamamdır (dikkate değer bir istisna saf işlevlerdir; onu yalnızca en soldaki öğesinde kullanabilirsiniz Alternatives
).
f@@@{f@a|b~g~1,#^2&@c|d@2}
f@@a|b|c
(Bunun yerine f@@{a,b,c}
) çalışmadığından Apply
, öncekinden daha yüksek önceliğe sahip olduğuna dikkat edin Alternative
.
Bu durumda, sadece kullanmanız gerekir f@@{a,b,c}
.
Operatör formları
Mathematica 10, “operatör formları” olarak adlandırılan temelde bazı fonksiyonların iyileştirilebileceği anlamına gelir. Bir işlevi kısmak, işleçlerinden birini düzelterek yeni bir işlev oluşturmaktır. Diyelim ki, SortBy[list, somereallylongfunction&]
çok fazla farklı list
s kullanıyorsunuz. Önce, muhtemelen atamıştır SortBy
etmek s
ve saf fonksiyon için f
So
s=SortBy;
f=somereallylongfunction&;
list1~s~f;
list2~s~f;
list3~s~f;
Şimdi körleyebilirsin SortBy
, yani şimdi yapabilirsin
s=SortBy[somereallylongfunction&];
s@list1;
s@list2;
s@list3;
Aynı şey, bunlarla sınırlı olmamak üzere, bir liste veya işlev argümanı alan pek çok başka işlev için Select
de geçerlidir.Map
, Nearest
vb
Mathematica.SE üzerinde ybeltukov bu tam bir listesini üretebildi :
{"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"}
Kompozisyon ve Doğru Kompozisyon
Composition
( @*
) Ve RightComposition
( /*
) için yeni kısa yollar var . Bunların karakterleri kurtarabileceği açıkça tartışılan bir örnek aşağıdaki üç eşdeğer satırda görülmektedir.
Last@Range@# & /@ Range[5]
Last@*Range /@ Range[5]
Range /* Last /@ Range[5]
Böyle bir koda gerek yoktur:
f[]:=DoSomething[1,2]
(*...*)
f[]
(*...*)
f[]
:=
Sağ tarafın tekrar değerlendirmesini zorlamak için bir değişkeni kullanabilirsiniz :
f:=DoSomething[1,2]
(*...*)
f
(*...*)
f
Bu aynı zamanda, sıkça yaptığınız herhangi bir işlemi (sadece bir şey olsa bile n++
) 5 bayt pahasına tek bir karaktere takma olabileceğiniz anlamına gelir . Öyleyse n++
, dördüncü kullanımdan sonra geri öder:
n++;n++;n++;n++
f:=n++;f;f;f;f
%
Ücretsiz bir değişken almak için kullanınBu ipucu, yalnızca Mathematica'nın REPL ortamının kabul edilebildiği durumlarda geçerlidir. %
Kod bir komut dosyası olarak çalıştırıldığında tanımlanmadı.
Ne zaman olabilir REPL özelliklerinden faydalanmak, bunu yapma:
a=someLongExpression;some[other*a,expression@a,using^a]
Bunun yerine, Mathematica'nın en son değerlendirilen (yeni satır sonlandırılmış) ifadeyi şu konumda sakladığını unutmayın %
:
someLongExpression;
some[other*%,expression@%,using^%]
Eklenen yeni satır bir bayt maliyeti, ancak kaldırarak iki a=
, bu nedenle genel olarak bu bir bayt kazandırır.
Bazı durumlarda (örneğin, a
yine de değerini yazdırmak istediğinizde ), ;
iki bayttan tasarruf ederek bile bırakabilirsiniz :
someLongExpression
some[other*%,expression@%,using^%]
Bir veya iki bayt oldukça küçük görünebilir, ancak bu önemli bir durumdur, çünkü tekrarlanan ifadelerin çıkarılmasını (bu çok yaygın bir tekniktir) golf oynarken çok daha faydalıdır:
Normal ifadelerin tekrarlanan ifadeleri çıkarması, ifadenin daha fazla kullanımıyla kaydedilmesi gereken, dört baytlık ek yük maliyetidir. Burada, herhangi bir şeyi kaydetmek için adlandırılmış bir değişkene ifade için bir ifadenin (ifadenin uzunluğuna göre) minimum kullanım sayısının kısa bir tablosu verilmiştir:
Length Min. Uses
2 6
3 4
4 3
5 3
6 2
... 2
Adsız değişkeni kullanarak, birkaç byte'ı daha sık kaydetmek mümkün olacaktır:
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
Golf oynamak için kullanılabileceğini düşünmüyorum %%
veya %n
kullanılabiliyor, çünkü en az iki kez kullanmazsanız, ifadeyi tam gereken yere koyabilirsiniz. İki kez kullanırsanız, değişken adındaki ek karakter, bazılarını atlamaktan kaynaklanan tasarrufları iptal eder x=
.
Bu esas olarak bir sonucudur bu uç ama bu kendi cevap garanti düşünüyorum yeterince yaygın bir görevdir.
Bir listenin olup olmadığını kontrol etmenin saf yolu kullanmaktır.
OrderedQ@a
Bir bayt ile daha iyi yapabiliriz
Sort@a==a
Ancak, zaten bir değişkeni kontrol etmek istediğimiz bir şey yoksa, bu işe yaramaz. ( Sort[a=...]==a
Gereksiz yere uzun sürecek bir şeye ihtiyacımız var.) Ancak, başka bir seçenek daha var:
#<=##&@@a
En iyi şey, bunun aynı byte sayısı için girişin ters sırada olup olmadığını kontrol etmek için kullanılmasıdır:
#>=##&@@a
A) liste elemanlarının farklı olduğunu ve b) 0 ile 9 arasında bir alt sınır (dahil; veya ters sıralı sıra için üst sınır):
0<##&@@a
5>##&@@a
Bunun neden işe yaradığını görmek için, tepedeki bağlantıdaki "Argümanların Sıraları" nı inceleyin.
##>0&@@a
. Sıralama için üst sınır için benzer.
Yerine StringRepeat[str,n]
kullanımı (0Range[n]+str)<>""
. Ya da str
herhangi bir alanın argümanlar bağlı değildir, hatta iyidir Array[str&,n]<>""
göre bu uç.
StringRepeat[s,n+1]
kullanım yerine Array[s&,n]<>s
(zaten n+1
bir değişkene sahipken bile ).
Table[str,n]<>""
Tersine sıralanan numaraların bir listesine ihtiyacınız varsa, kullanmayın.
Reverse@Sort@x
fakat
-Sort@-x
altı bayt kaydetmek için. Negatif bir değere göre sıralama ayrıcaSortBy
senaryolar :
Reverse@SortBy[x,Last]
SortBy[x,-Last@#&]
-Sort@-x
?
Break
Bir veya iki karakter kaydedebileceğiniz bir ifadeyi yapıştırabilirsiniz . Örnek ( diğer detaylar netlik için oylanmamıştır ):
result = False;
Break[]
dönüştürülebilir
Break[result = False]
Bir karakter kaydetmek için Söz konusu ifade, işlev uygulamasından daha düşük önceliğe sahip değilse, başka bir karakteri bile kaydedebilirsiniz:
Print@x;
Break[]
dönüştürülebilir
Break@Print@x
Belgelenmemiş olmasına rağmen, argüman Break
potansiyel olarak daha fazla tasarruf sağlayabilecek olan çevre döngüsünden döndürülmüş gibi görünüyor.
Tüm boşlukları bir dizeden kaldırmak s
için
StringSplit@s<>""
Başka bir deyişle, StringSplit
varsayılanı kullanın (boşluk olmayan bileşenlere bölün) ve bunları bir araya getirin. Başka herhangi bir karakterden veya alt diziden kurtulmak istiyorsanız, aynı durum halen en kısa olanıdır:
s~StringSplit~"x"<>""
Range
Çok yaygın bir görev, 1'den 1'e kadar olan tüm sayılara bir işlev işlevi uygulamaktır n
(genellikle giriş olarak verilir). Bunu yapmanın esasen 3 yolu vardır (örnek olarak adlandırılmamış bir kimlik işlevi kullanarak):
#&/@Range@n
Array[#&,n]
Table[i,{i,n}]
İlki için gitme eğilimindeyim (ne olursa olsun), ama bu nadiren en iyi seçimdir.
Array
yerineYukarıdaki örnek, kullanımın Array
aynı bayt sayısına sahip olduğunu gösterir . Ancak, tek bir ifade olması avantajına sahiptir. Özellikle, sonucu bir işlevle daha fazla işlemek f
istiyorsanız, bir bayttan tasarruf eden önek notasyonu kullanabilirsiniz Range
:
f[#&/@Range@n]
f@Array[#&,n]
Ayrıca Range
, örneğin , ihtiyaç duyduğunuz isimlendirilmemiş işleve ilişkin parantezleri atabilirsiniz.
15/(#&)/@Range@n
15/Array[#&,n]
Eğer varsa yok (ya da daha az öncelik olan bir operatör ile) daha da kullanmak istiyorum, bunun yerine yazabilirsiniz Array
infix gösterimde ve aynı zamanda bir byte tasarruf kendisini:
#&/@Range@n
#&~Array~n
Dolayısıyla, Array
neredeyse kesinlikle daha iyidir Range
.
Table
yerineŞimdi tablo 3 bayt veya en az 2 olmak üzere, ekleme notasyonu bir seçenekse:
#&/@Range@n
i~Table~{i,n}
Ne zaman değil infix gösterimi kullanarak, Table
sizin fonksiyonu çeşitli tablolar barındırdığı takdirde parantez atlamak için izin verebilir:
(#;#)&/@Range@n
Table[i;i,{i,n}]
Bu hala daha uzun, ancak aşağıda belirtilen durumlarda ekstra tasarruf sağlıyor.
Gerçek tasarruf Table
, çalışan değişkene bir isim veren durumdan kaynaklanmamalıdır. Genelde, dış değişkeni iç işlevlerden birinin içinde kullanmak istediğiniz adlandırılmamış işlevleri iç içe geçirirsiniz. Bu olduğu zaman, şundan Table
daha kısadır Range
:
(i=#;i&[])&/@Range@n
Table[i&[],{i,n}]
i&[]~Table~{i,n}
Karakterleri atamak için kaydetmekle kalmaz i
, aynı zamanda işlevini tek bir ifadeye indirgeyebilir ve bu işlem üzerine ek notasyonu kullanabilirsiniz. Başvuru için, Array
bu durumda da daha uzun, ancak yine de daha kısa Range
:
(i=#;i&[])&~Array~n
Range
?Değerleri işlemek için bir fonksiyon çağrısına ihtiyacınız olmadığında, örneğin haritalandırma bir vektör işlemiyle gerçekleştirilebildiğinde. Örneğin:
5#&~Array~n
5Range@n
#^2&~Array~n
Range@n^2
Elbette, herhangi bir işlevi eşleştirmek istemiyorsanız, örneğin daha kısadır, örn.
Mean@Array[#&,n]
Mean@Range@n
f/@Range[x]
düzenli olarak kullanan biri ...
Gibi bazı yapı olduğu gibi i=1;While[cond[i],i++]
iyi, ancak iki bayt daha kısa bir alternatif var:
1//.i_/;cond[i]:>i+1
Yukarıdaki kod tekrar tekrar yerine geçmekte i
olan i+1
bu durum karşılarken cond[i]
. Bu durumda, i
başlar1
.
Varsayılan maksimum yineleme sayısının 2 ^ 16 (= 65536) olduğuna dikkat edin. Bundan daha fazla tekrarlamaya ihtiyacınız olursa daha While
iyi olurdu. ( MaxIterations->∞
çok uzun)
Bazen değiştirebilirsin If
bir mantıksal işleçle .
Örneğin, bir sayının asal olup olmadığını kontrol eden bir işlev yapmak istediğinizi varsayalım ve 2*(number) - 1
doğruysa yazdırın :
If[PrimeQ@#,Print[2#-1]]&
Bunun &&
yerine kullanırsanız daha kısa olur :
PrimeQ@#&&Print[2#-1]&
Birden çok ifadeniz olsa bile, yine de baytları kurtarırsınız:
If[PrimeQ@#,a++;Print[2#-1]]&
PrimeQ@#&&a++&&Print[2#-1]&
(* or *)
PrimeQ@#&&(a++;Print[2#-1])&
||
Koşulun olmasını istediğiniz durumlarda kullanabilirsiniz False
:
If[!PrimeQ@#,Print[2#-1]]&
(* or *)
If[PrimeQ@#,,Print[2#-1]]&
(* can become *)
PrimeQ@#||Print[2#-1]&
Bu hileler işe yarar çünkü mantıksal operatörler kısa devre yapabilir ; İkinci argüman ve daha sonra geçerli bir boole ifadeleri olması gerekmez.
Tabii ki, bu If
ya geri dönüş değerine ihtiyacınız varsa ya da hem gerçek hem de sahte argümanlara ihtiyacınız olduğunda işe yaramaz If
.
Burada, birçok şeyi kısaltabilen çok sayıda operatör giriş formu listesi . Bunlardan bazıları diğer yayınlarda belirtilmiştir, ancak liste uzundur ve orada birkaç yeni şey bulmaya şaşırdım:
Optional (:)
Optional (:)
genişletme için ayrı bir kural tanımlamak zorunda kalmadan değiştirmelerdeki listeleri genişletmek için kullanılabilir.
Bu cevap bana göre ve @ngenisis tarafından bu cevap örnekleridir.
kullanım
... /. {p___, a_: 0, b_, q___} /; cond[b] :> ...
Yukarıdaki değiştirme ilk önce deseni kullanır {p___, a_, b_, q___}
ve öyle bir eşleşme bulurb
belirli bir koşulu karşılayacak şekilde bir .
Böyle bir eşleşme bulunamadığında, çıkarır a_
ve bunun yerine arar {p___, b_, q___}
.a
Aramaya dahil edilmez ve değere sahip olduğu varsayılır 0
.
İkinci kalıp arama işleminin yalnızca b
listenin başında gerçekleştiğine dikkat edin; Eğer birb
Bir koşulu sağlayan değer ortada ise, {p___, a_, b_, q___}
(daha yüksek önceliğe sahip) bunun yerine eşleşir.
Bunun yerine, listenin başında tatmin edici bir durum meydana 0
geldiğinde a hazırlığına eşdeğerdir b
. (yani ayrı bir kural tanımlamaya gerek yoktur, {b_, q___} /; cond[b] :> ...
)
Golf kodu için, saf Function
argümanlara en yaygın şekilde Slot
s; örneğin #
, birinci argüman #2
için, ikincisi için, vs. ( daha fazla ayrıntı için bu cevaba bakınız).
Çoğu durumda, Function
s yuvalamak isteyeceksiniz . Örneğin, 1##&@@#&
a, Function
ilk değişken olarak bir listesini alır ve elemanları ürün verir ki. İşte bu fonksiyon TreeForm
:
Üst seviyeye geçen argümanlar Function
yalnızca en üst seviyede bulunan Slot
s ve SlotSequence
s'leri doldurabilir ; bu durumda SlotSequence
iç kısımda Function
, argümanlara en üst seviyeye ulaşmanın hiçbir yolu olmayacaktır.Function
.
Bununla birlikte, bazı durumlarda, argümanları dışa yönlendirebilmek için Function
başka bir iç içe geçmiş yuva isteyebilirsiniz . Örneğin , işlevin üst seviyedeki bir argümana bağlı olduğu gibi bir şey isteyebilirsiniz . Somutluk için, diyelim ki giriş modülünün karesinin kalanını girişi en üst seviyeye vermelidir . Bunu başarmanın bir yolu, bir değişkene üst seviye argümanı atamaktır:Function
Function
Array[fun,...]&
fun
Function
fun
Function
(x=#;Array[Mod[#^2,x]&,...])&
İçinde nerede x
belirirseFunction
Mod[#^2,x]&
, bu dış ilk bağımsız değişken değinecektir Function
, oysa #
iç ilk bağımsız değişken değinecektir Function
. Daha iyi bir yaklaşım, Function
ilk argümanın Function
(isimsizlerin aksine Slot
) isimlendirilmiş argümanları temsil edecek bir sembol veya sembol listesi olduğu iki argüman formuna sahip olan gerçeğini kullanmaktır . Bu da bize bu durumda üç bayt kazandırıyor:
xArray[Mod[#^2,x]&,...]
U+F4A1
İkili infix operatörünü temsil eden üç bayt özel kullanım karakteridir \[Function]
. Ayrıca Function
başka bir içindeki ikili biçimi de kullanabilirsiniz Function
:
Array[xMod[x^2,#],...]&
Bu, yukarıdakilere eşdeğerdir. Bunun nedeni, eğer adlandırılmış argümanlar kullanıyorsanız, o zaman Slot
s ve yukarıda adlandırılmış argümanlar kullanmayan bir SlotSequences
sonraki gruba ait olduğu varsayılır Function
.
Şimdi sadece Function
bu şekilde yuvalayabildiğimiz için , her zaman yapmamız gerektiği anlamına gelmez. Örneğin, bir listenin girdilerden daha az olan bu öğelerini seçmek istiyorsak, aşağıdakine benzer bir şeyler yapmak için cazip olabiliriz:
Select[...,xx<#]&
Cases
İç içe geçme ihtiyacını Function
tamamen kullanmaktan kaçınmak aslında daha kısa olacaktır :
Cases[...,x_/;x<#]&
Etrafta çalışarak bir bayt tasarruf edebilirsiniz Prepend
veya PrependTo
:
l~Prepend~x
{x}~Join~l
{x,##}&@@l
veya
l~PrependTo~x
l={x}~Join~l
l={x,##}&@@l
Ne yazık ki, bu daha yaygın Append
olanlara yardımcı olmuyor, bu da Array.push()
diğer dillerdeki en kısa eşdeğer gibi görünüyor .
BlockMap
olduğunuPartition
+Map
Bu ipucu aynı zamanda “Bunların hepsini içeren sürüm notlarını oku” başlıklı olabilir. (Başvuru için, işte 10.2 ve bugün 10.3 sürümünün sürüm notlarıdır .)
Her neyse, küçük sürümler bile çok sayıda yeni özellik içerir ve 10.2'den itibaren (golf oynamak için) daha faydalı olanlardan biri yeni BlockMap
fonksiyondur. Temelde birleştiriyor Partition
ve Map
golfçüler için harika, çünkü Partition
oldukça sık kullanılıyor ve bu gerçekten sinir bozucu bir fonksiyon ismi. Yeni işlev kendiliğinden kısalmayacaktır Partition
, ancak ne zaman bir işlevi bölümlere eşlemek istediğinizde (bu muhtemelen daha sık olmaz), şimdi bir veya iki bayt kaydedebilirsiniz:
#&/@l~Partition~2
BlockMap[#&,l,2]
#&/@Partition[l,3,1]
BlockMap[#&,l,3,1]
Adsız fonksiyonun yeni konumu kendinize bazı parantezleri kaydetmenize izin verdiğinde tasarruflar daha da artar:
#&@@(#&/@Partition[l,3,1])
#&@@BlockMap[#&,l,3,1]
Ne yazık ki, neden eklemediğini de bilmiyorum BlockApply
onlar de bilmiyorum ...
Ayrıca döngüsel bir liste elde etmek için BlockMap
kullanabileceğiniz 4. parametreyi desteklemediğine dikkat edin 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... *)
Cevabınız aynı işlevleri veya ifadeleri birden çok kez kullanmakla sona ererse, bunları değişkenlere kaydetmeyi düşünebilirsiniz.
İfadeniz uzunsa l
ve n
süreleri kullanıyorsanız, normalde l * n
bayt kullanır .
Bununla birlikte, bir uzunluk-1 değişkeninde saklarsanız, sadece 3 + l + n
bayt alır (veya 2 + l + n
değişkeni gerekmeyeceğiniz yere CompoundExpression (;)
veya parantez içine atarsanız ).
Örneğin, basit bir problem düşünelim, ikizlerden N'den daha az primer bulalım .
Biri bu 54 baytlık çözümü yazabilir:
Select[Range@#,PrimeQ@#&&(PrimeQ[#+2]||PrimeQ[#-2])&]&
Bu örnekte, işlev PrimeQ
üç kez kullanılır.
PrimeQ
Bir değişken adı atayarak , bayt sayısı azaltılabilir. Aşağıdakilerin her ikisi de 48 bayttır (54 - 6 bayt):
Select[p=PrimeQ;Range@#,p@#&&(p[#+2]||p[#-2])&]&
Select[Range@#,(p=PrimeQ)@#&&(p[#+2]||p[#-2])&]&
Sort
yerineSortBy
Gibi listeler için list = {{1, "world"}, {0, "universe"}, {2, "country"}}
, aşağıdaki üç ifade neredeyse eşdeğerdir.
SortBy[list,#[[1]]&]
list~SortBy~First
Sort@list
Select
veSortBy
Bazen girişleri daha büyük bir setten seçip, minimum / maksimum bulmak için bunları sıralamamız gerekir. Bazı şartlar altında iki operasyon bir kombine edilebilir.
Örneğin, asgari olarak, aşağıdaki iki ifade neredeyse eşdeğerdir.
SortBy[Select[l,SomeFormula==SomeConstant&],SortValue&]
SortBy[l,SortValue+99!(SomeFormula-SomeConstant)^2&]
ve
SortBy[Select[l,SomeFormula!=SomeConstant&],SortValue&]
SortBy[l,SortValue+1/(SomeFormula-SomeConstant)&]
1/0
dır-dir ComplexInfinity
tüm gerçek sayılar daha "büyük" olan.
Bir anahtar-değer listesi için, örneğin:
{SortValue,#}&/@SortBy[Select[l,SomeFormula==SomeConstant],SortValue&]
Sort[{SortValue+99!(SomeFormula-SomeConstant)^2,#})&/@l]
Array
ile##&
Düzleştirilmesi gereken sonuçların bir listesini hesaplamak için çok boyutlu bir Dizi kullanırken ##&
, dördüncü argüman olarak kullanın . Bu, Array'ın kafalarını bunun yerine ##&
(ile eşdeğer Sequence
) ile değiştirir List
, bu nedenle nihai sonuç (düz) Sequence
bir sonuç olur.
İki boyutta karşılaştırın
{Array[f,dims,origin,##&]}
Join@@Array[f,dims,origin]
Tabii ki,
Join@@Array[f,dims]
hala 2 (veya 3, eğer ek gösterim kullanılabilirse), bayttan daha kısadır
{Array[f,dims,1,##&]}
.
Üç veya daha fazla boyutta, {Array[f,dims,origin,##&]}
başlangıç noktası 1 olsa bile, alternatiften her zaman daha kısadır.
{Array[f,dims,1,##&]}
f~Array~dims~Flatten~2
Varsayılan değerler eksik kalıp argümanlarını verimli bir şekilde ele alır. Örneğin, Exp[c_*x]
herhangi bir değer için bir kuralda eşleşmeyi desenlemek istiyorsak c
, naif
Exp[x] + Exp[2x] /. {Exp[c_*x] -> f[c], Exp[x] -> f[1]}
(* f[1] + f[2] *)
c
eksik olan zaman için varsayılan değeri kullandığımızdan çok daha fazla bayt kullanır :
Exp[x] + Exp[2 x] /. Exp[c_.*x] -> f[c]
(* f[1] + f[2] *)
Bir varsayılan kullanımı deseni sonra bir nokta ile belirtilir: c_.
.
Yukarıdaki örnekte, bir işlemdir: varsayılan değerler operasyonları ile ilişkilidir Times
olarak c_.*x
ve eksik bir değer c_
, böylece ilişkili varsayılan değer alınır Times
için 1'dir Plus
, varsayılan değer 0'dır:
Exp[x] + Exp[x + 2] /. Exp[x + c_.] -> f[c]
(* f[0] + f[2] *)
İçin Power
üstler, varsayılan 1'dir:
x + x^2 /. x^n_. -> p[n]
(* p[1] + p[2] *)
(Norm[#-#2]&)
yerineEuclideanDistance
.