Bạn có lời khuyên chung nào cho việc chơi golf ở Julia? 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 Julia (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 ở Julia? 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 Julia (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:
LƯU Ý: Dưới đây có thể chứa một số mẹo đã lỗi thời, vì Julia chưa hoàn toàn ổn định về mặt cấu trúc.
Một vài thủ thuật để cứu một vài nhân vật
\ =div
và sau đó bạn có thể nhập a\b
thay vì div(a,b)
. Lưu ý không gian - điều này là cần thiết để tránh phân tích cú pháp dưới dạng toán tử "\ =". Cũng lưu ý rằng, nếu quá tải ở mức nhắc REPL, hãy sử dụng (\)=Base.(\)
hoặc \ =Base. \
để đặt lại. Chú ý: một số chức năng đã hiện có UTF-8 khai thác được xác định trước, chẳng hạn như ÷
cho div
, như ghi nhận của Alex A.a>0?"Hi":""
sử dụng "Hi"^(a>0)
để lưu một byte hoặc cho boolean a, sử dụng"Hi"^a
để lưu ba byte.a=split("Hi there"," ")
, bạn có thể tránh a[1]
và a[2]
bằng cách sử dụng a,b=split("Hi there"," ")
, có thể được tham chiếu là a
và b
, tiết kiệm ba byte cho mỗi lần sử dụng, với chi phí chỉ bằng hai ký tự phụ khi gán. Rõ ràng, không làm điều này nếu bạn có thể làm việc với các hoạt động vector.[]
- cho các mảng, biểu thức A[]
tương đương với A[1]
. Lưu ý rằng điều này không hoạt động đối với Chuỗi nếu bạn muốn lấy ký tự đầu tiên hoặc cho Tuples.==[]
cho mảng và ==()
cho tuple; tương tự, đối với tiêu cực, sử dụng !=[]
và !=()
. Đối với chuỗi, sử dụng ==""
cho trống, nhưng sử dụng>""
cho không trống, vì "" là từ vựng trước bất kỳ chuỗi nào khác.x<=1&&"Hi"
có thể được viết dưới dạng x>1||"Hi"
, lưu một ký tự (miễn là sự trở lại của boolean không quan trọng).in('^',s)
thay vì contains(s,"^")
. Nếu bạn có thể sử dụng các ký tự khác, bạn có thể tiết kiệm thêm một chút với '^'∈s
, nhưng lưu ý rằng∈
là 3 byte trong UTF-8.minimum(x)
hoặc maximum(x)
, sử dụng min(x...)
hoặc max(x...)
, để loại bỏ một ký tự khỏi mã của bạn, nếu bạn biết x
sẽ có ít nhất hai yếu tố. Ngoài ra, nếu bạn biết tất cả các yếu tố x
sẽ không âm, hãy sử dụng minabs(x)
hoặcmaxabs(x)
r"(?m)match^ this"
, nhập r"match^ this"m
, lưu ba ký tự.reverse(x)
dài hơn một byte flipud(x)
và sẽ thực hiện cùng một hoạt động, do đó, mảng sau tốt hơn.{[1,2]}
không phải {1,2}
) - đối với Julia 0.4, bạn sẽ cần Any[[1,2]]
.end
trong lập chỉ mục mảng, nó sẽ tự động được chuyển đổi theo chiều dài của mảng / chuỗi. Vì vậy, thay vì k=length(A)
sử dụng A[k=end]
để lưu 3 ký tự. Lưu ý rằng điều này có thể không có lợi nếu bạn muốn sử dụng k ngay lập tức. Điều này cũng hoạt động trong trường hợp đa chiều - A[k=end,l=end]
sẽ có kích thước của mỗi kích thước A
- tuy nhiên, (k,l)=size(A)
ngắn hơn một byte trong trường hợp này, vì vậy chỉ sử dụng nó nếu bạn muốn truy cập ngay vào phần tử cuối cùng cùng một lúc.A[k=1:end]
, trong trường hợp đó k
sẽ giữ một phép lặp khớp 1:length(A)
. Điều này có thể hữu ích khi bạn cũng muốn sử dụng mảng A
cùng một lúc.collect(A)
sử dụng [A...]
, điều này sẽ làm điều tương tự và tiết kiệm 4 byte."$(s[i])"
hoặc dec(s[i])
cho các biểu thức hoặc biến đa ký tự và "$i"
cho các biến ký tự đơn.?:
thay vì &&
hoặc ||
cho phép gán có điều kiện - nghĩa là, nếu bạn muốn thực hiện một phép gán chỉ trong một số điều kiện, bạn có thể lưu một byte bằng cách viết cond?A=B:1
thay vì cond&&(A=B)
, hoặc cond?1:A=B
hơn là cond||(A=B)
. Lưu ý rằng 1
, ở đây, là một giá trị giả.union
hoặc ∪
thay vìunique
- union(s)
sẽ thực hiện tương tự như unique(s)
và lưu một byte trong quy trình. Nếu bạn có thể sử dụng các ký tự không phải ASCII, thì ∪(s)
sẽ làm điều tương tự và ∪
chỉ tốn 3 byte thay vì 5 byte trong union
.split("Hi there")
vì đối số mẫu mặc định là khoảng trắng .
Các toán tử xác định lại có thể lưu rất nhiều byte trong ngoặc đơn và dấu phẩy.
Đối với một ví dụ đơn nhất, hãy so sánh các triển khai đệ quy sau đây của chuỗi Fibonacci:
F(n)=n>1?F(n-1)+F(n-2):n # 24 bytes
!n=n>1?!~-n+!(n-2):n # 20 bytes
!n=n>1?!~-n+!~-~-n:n # 20 bytes
Toán tử được xác định lại vẫn giữ quyền ưu tiên ban đầu của nó.
Lưu ý rằng chúng tôi không thể đơn giản trao đổi !
theo hướng có lợi ~
, vì ~
đã được xác định cho số nguyên, trong khi!
chỉ được xác định cho Booleans.
Ngay cả khi không có đệ quy, việc xác định lại toán tử vẫn ngắn hơn xác định hàm nhị phân. So sánh các định nghĩa sau đây của một thử nghiệm chia hết đơn giản.
f(x,y)=x==0?y==0:y%x==0 # 23 bytes
(x,y)->x==0?y==0:y%x==0 # 23 bytes
x->y->x==0?y==0:y%x==0 # 22 bytes
x\y=x==0?y==0:y%x==0 # 20 bytes
Sau đây minh họa cách xác định lại toán tử nhị phân để tính toán hàm Ackermann:
A(m,n)=m>0?A(m-1,n<1||A(m,n-1)):n+1 # 35 bytes
^ =(m,n)->m>0?(m-1)^(n<1||m^~-n):n+1 # 36 bytes
| =(m,n)->m>0?m-1|(n<1||m|~-n):n+1 # 34 bytes
m\n=m>0?~-m\(n<1||m\~-n):n+1 # 28 bytes
Lưu ý rằng ^
thậm chí còn dài hơn so với việc sử dụng một định danh thông thường, vì mức độ ưu tiên của nó quá cao.
Như đã được đề cập trước đó
m|n=m>0?m-1|(n<1||m|~-n):n+1 # 28 bytes
sẽ không hoạt động cho các đối số nguyên, vì |
đã được xác định trong trường hợp này. Định nghĩa cho số nguyên có thể được thay đổi với
m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes
nhưng điều đó quá dài Tuy nhiên, nó không làm việc nếu chúng ta vượt qua một phao như là đối số bên trái và một số nguyên như là đối số đúng.
Đừng quá dễ dàng bị quyến rũ bởi yếu tố (n) Hàm thư viện cơ sở hấp dẫn factor(n)
có một lỗ hổng nghiêm trọng: nó trả về hệ số của số nguyên của bạn trong một Dict
loại không có thứ tự . Do đó, nó đòi hỏi tốn kém collect(keys())
và collect(values())
cũng có khả năng a cat
và a sort
để có được dữ liệu bạn muốn từ nó. Trong nhiều trường hợp, có thể rẻ hơn nếu chỉ tính theo phân chia thử nghiệm. Đáng buồn nhưng là sự thật.
Sử dụng bản đồ map
là một thay thế tuyệt vời để lặp. Hãy nhận biết sự khác biệt giữa map
và map!
khai thác chức năng tại chỗ của cái sau khi bạn có thể.
Sử dụng mapreduce mapreduce
mở rộng chức năng của bản đồ hơn nữa và có thể là một trình tiết kiệm byte đáng kể.
Chức năng ẩn danh là tuyệt vời! .. đặc biệt khi được chuyển đến các map
chức năng đã nói ở trên .
Chức năng mảng tích lũy cumprod
, cumsum
thì hương vị cummin
và các chức năng tương tự đặt tên khác cho phép hoạt động tích lũy cùng một chiều hướng nhất định một mảng n chiều. (Hoặc * un * được chỉ định nếu mảng là 1-d)
Ký hiệu ngắn cho bất kỳ Khi nào bạn muốn chọn tất cả một thứ nguyên cụ thể của mảng đa chiều (hoặc Dict), ví dụ: A[Any,2]
bạn có thể lưu byte bằng cách sử dụngA[:,2]
Sử dụng ký hiệu một dòng cho các chức năng Thay vì function f(x) begin ... end
bạn thường có thể đơn giản hóa đểf(x)=(...)
Sử dụng toán tử ternary Nó có thể là một trình tiết kiệm không gian cho các cấu trúc đơn biểu thức If-Then-Else. Hãy cẩn thận: Mặc dù có thể trong một số ngôn ngữ khác, bạn không thể bỏ qua phần sau dấu hai chấm trong Julia. Ngoài ra, toán tử là mức biểu thức trong Julia, vì vậy bạn không thể sử dụng nó để thực thi có điều kiện toàn bộ khối mã.
if x<10 then true else false end
đấu với
x<10?true:false
Điều này cũng có thể trong các ngôn ngữ khác, nhưng thường dài hơn phương pháp đơn giản. Tuy nhiên, khả năng của Julia để xác định lại các nhà khai thác đơn nhất và nhị phân của nó làm cho nó khá golf.
Ví dụ: để tạo bảng cộng, trừ, nhân và chia cho các số tự nhiên từ 1 đến 10, người ta có thể sử dụng
[x|y for x=1:10,y=1:10,| =(+,-,*,÷)]
mà định nghĩa lại các nhị phân tử |
như +
, -
, *
và ÷
, sau đó tínhx|y
cho từng hoạt động và x
vày
trong phạm vi mong muốn.
Điều này làm việc cho các nhà khai thác đơn phương là tốt. Ví dụ, để tính các số phức 1 + 2i , 3-4i , -5 + 6i và -7-8i , các phủ định của chúng, các liên hợp phức tạp và nghịch đảo nhân của chúng, người ta có thể sử dụng
[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]
mà định nghĩa lại unary nhà điều hành ~
như +
, -
, conj
và inv
, sau đó tính~x
cho tất cả các số phức mong muốn.
Trình tự nữ và nam (nhị phân)
Hoán vị trường hợp (đơn phương)
Từ khóa đôi khi có thể ngay lập tức theo các hằng số mà không cần dấu cách hoặc dấu chấm phẩy. Ví dụ:
n->(for i=1:n n-=1end;n)
Lưu ý thiếu không gian giữa 1
và end
. Điều này cũng đúng cho việc end
xảy ra sau một paren gần, tức là )end
.
Thực hiện phân chia số nguyên bằng cách sử dụng ÷
thay vì div()
hoặc quá tải một toán tử. Lưu ý rằng ÷
có giá trị 2 byte trong UTF-8.
Sử dụng vec()
hoặc A[:]
(cho một số mảng A
) chứ không phải reshape()
bất cứ khi nào có thể.
Tạo các chức năng thay vì các chương trình đầy đủ khi được phép trong các quy tắc thử thách. Nó ngắn hơn để xác định một hàm chấp nhận đầu vào thay vì xác định các biến bằng cách đọc từ stdin. Ví dụ:
n->(n^2-1)
n=read(STDIN,Int);n^2-1
Các biến có thể được tăng bên trong đối số thành hàm. Ví dụ, sau đây là câu trả lời của tôi cho thử thách Tìm số nhị phân thưa thớt 1 tiếp theo :
n->(while contains(bin(n+=1),"11")end;n)
Điều này là ngắn hơn so với tăng n
bên trong của vòng lặp.
Được giới thiệu trong Julia 0,5. Nó giống như bản đồ, nhưng sử dụng ít ký tự hơn và thực hiện hành vi phát sóng trên nó - điều đó có nghĩa là bạn có thể viết ít lambda hơn để giải quyết mọi việc.
Thay vì:
map(f,x)
-- 8 ký tự.f.(x)
- 5 ký tựVẫn tốt hơn:
map(a->g(a,y),x)
- 16 ký tựg.(x,[y])
- 9 ký tự