Lời khuyên cho việc chơi golf ở Julia


20

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:


19

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

  1. Toán tử quá tải với các hàm nhị phân được sử dụng thường xuyên . Ví dụ: nếu bạn cần thực hiện nhiều phép chia số nguyên và không cần phân chia nghịch đảo, hãy sử dụng \ =divvà sau đó bạn có thể nhập a\bthay 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.
  2. Sử dụng ^ với chuỗi cho đầu ra có điều kiện . Đó là, thay vì 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.
  3. (đôi khi) Lưu trữ các vectơ kích thước cố định nhỏ dưới dạng các biến riêng biệt . Chẳng hạn, thay vì a=split("Hi there"," "), bạn có thể tránh a[1]a[2]bằng cách sử dụng a,b=split("Hi there"," "), có thể được tham chiếu là ab, 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.
  4. Truy cập phần tử đầu tiên của Array với[] - 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.
  5. Không sử dụng isempty cho Mảng, Tuples hoặc Chuỗi - thay vào đó, sử dụng ==[]cho mảng và ==()cho tuple; tương tự, đối với tiêu cực, sử dụng !=[]!=(). Đố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.
  6. Sử dụng toán tử boolean ngắn mạch bên phải thay cho "if" . Nó có thể ít hơn một chút về Julia, nhưng nó đáng để lưu tâm. 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).
  7. Không sử dụng chứa để kiểm tra sự hiện diện của ký tự trong chuỗi - nếu bạn bị giới hạn ở ASCII cơ bản, hãy sử dụ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.
  8. Tìm kiếm các giá trị tối thiểu / tối đa trong một mảng? Không sử dụng tối thiểu hoặc tối đa - thay vì sử dụng 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 xsẽ 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ố xsẽ không âm, hãy sử dụng minabs(x)hoặcmaxabs(x)
  9. Nếu có thể và được cho phép bởi thử thách, hãy sử dụng một dòng mới thực tế thay vì \ n - lưu ý rằng điều này sẽ làm cho mã của bạn khó đọc hơn và có thể có nghĩa là bạn cần cung cấp một phiên bản "không được cung cấp" để mọi người có thể thực sự hiểu nó
  10. Đặt các tùy chọn sau chuỗi regex - nếu bạn muốn có chuỗi regex ở chế độ đa dòng, ví dụ: không nhập r"(?m)match^ this", nhập r"match^ this"m, lưu ba ký tự.
  11. Đảo ngược các mảng 1-D bằng flipud - 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.
  12. Nếu có thể, hãy sử dụng nối mảng thay vì đẩy!, Unshift!, Nối!, Hoặc trả trước! - đối với mảng bình thường, điều này có thể được thực hiện dễ dàng. Đối với mảng kiểu Bất kỳ với các thành phần mảng, bạn sẽ cần dấu ngoặc nhọn xung quanh các mảng đã thêm (nghĩa là {[1,2]}không phải {1,2}) - đối với Julia 0.4, bạn sẽ cần Any[[1,2]].
  13. Sử dụng lập chỉ mục mảng để lấy kích thước của một mảng hoặc chuỗi - khi bạn sử dụng endtrong 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.
  14. Nhận một trình lặp chỉ mục bằng cách sử dụng lập chỉ mục mảng - Tương tự như 13, bạn cũng có thể có được một trình vòng lặp khớp với độ dài của một mảng bằng cách sử dụng A[k=1:end], trong trường hợp đó ksẽ 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 Acùng một lúc.
  15. Không sử dụng thu thập để chuyển đổi một chuỗi thành một mảng char - thay vì 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.
  16. Cần một số chuyển đổi thành một chuỗi? Sử dụng "$(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.
  17. Sử dụng ?: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:1thay vì cond&&(A=B), hoặc cond?1:A=Bhơn là cond||(A=B). Lưu ý rằng 1, ở đây, là một giá trị giả.
  18. Sử dụng unionhoặ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.

2
Ôi làm thế nào tôi thích trò lừa đầu tiên trong Python.
hẹn gặp

Bạn có thể phân tách trên các khoảng trắng bằng cách sử dụng đơn giản split("Hi there")vì đối số mẫu mặc định là khoảng trắng .
Alex A.

@AlexA. - Tôi biết, nhưng đó không phải là điểm mấu chốt, và tiền boa cũng áp dụng như nhau.
Glen O

Điểm 12 đã thay đổi trong 0,5.
Lyndon White

@Oxinabox - Tôi không ngạc nhiên, tôi khá chắc chắn rằng một vài trong số chúng đã lỗi thời. Ban đầu tôi đã viết hầu hết các lời khuyên cho 0,3, tôi nghĩ vậy.
Glen O

15

Xác định lại toán tử để xác định hàm

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.

Toán tử đệ quy

Đố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

Hãy thử trực tuyến!

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.

Toán tử nhị phân

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

Hãy thử trực tuyến!

Toán tử nhị phân đệ quy

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

Hãy thử trực tuyến!

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.


11
  1. Đừ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 Dictloại không có thứ tự . Do đó, nó đòi hỏi tốn kém collect(keys())collect(values())cũng có khả năng a catvà 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.

  2. 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 mapmap!khai thác chức năng tại chỗ của cái sau khi bạn có thể.

  3. 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ể.

  4. Chức năng ẩn danh là tuyệt vời! .. đặc biệt khi được chuyển đến các mapchức năng đã nói ở trên .

  5. Chức năng mảng tích lũy cumprod , cumsumthì hương vị cumminvà 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)

  6. 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]

  7. Sử dụng ký hiệu một dòng cho các chức năng Thay vì function f(x) begin ... endbạn thường có thể đơn giản hóa đểf(x)=(...)

  8. 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


3
Làm thế nào trên trái đất là "sử dụng toán tử ternary" hơi cụ thể cho Julia? Nó liên quan đến mọi ngôn ngữ có nó.
Peter Taylor

5
Nó có liên quan rằng nó có nó. Nhiều ngôn ngữ cũng có chức năng ánh xạ, ẩn danh hoặc thuần túy, một số loại tốc ký cho bất kỳ / tất cả, chức năng tích lũy, v.v. .
Jonathan Van Matre 17/03/2016

3
Trời ạ, chỉ có tất cả các chức năng cho người mới bắt đầu, nơi mọi thứ trả về một giá trị vì vậy một op ternary sẽ là dư thừa. Nếu bạn phải có ví dụ cụ thể: Go, Haskell, Scala, Lua, VB, Prolog, PL / SQL ... thậm chí Python không có trong nhiều phiên bản. Trong số gần chục ngôn ngữ có chủ đề mẹo đề cập đến toán tử ternary của họ, có lý do nào khiến bạn chỉ chọn trở thành tỉnh trong tôi không?
Jonathan Van Matre 17/03/2016

3
Chà, này, ít nhất bạn là một giáo sĩ có cơ hội bình đẳng. ( ̄ ー  ̄ ヘ)
Jonathan Van Matre 17/03/2016

1
Tôi có thể đề nghị điều chỉnh mẹo 3 không? mapreduce dài hơn mapprintl hoặc mapprintr và có thể có hành vi khác nhau tùy theo việc thực hiện. mapprintl và mapprintr là liên kết trái và phải (tương ứng) một cách nhất quán, và do đó là một lựa chọn tốt hơn. Điều này cũng áp dụng chung hơn để giảm (sử dụng Foldl hoặc Foldr).
Glen O

9

Lặp lại các chức năng

Đ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ư +, -, *÷, sau đó tínhx|y cho từng hoạt động và xy 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-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ư +, -, conjinv, sau đó tính~x cho tất cả các số phức mong muốn.

Ví dụ trong các cuộc thi thực tế


6
  1. 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 1end. Điều này cũng đúng cho việc endxảy ra sau một paren gần, tức là )end.

  2. 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.

  3. 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ể.

  4. 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
  5. 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 nbên trong của vòng lặp.


6
  1. Loại khôngreturn f(x)=x+4 giống hệt nhưng ngắn hơnf(x)=return x+4 . Julia luôn trả về kết quả của tuyên bố cuối cùng.
  2. Sử dụng = thay vì trong . [x for x in 1:4]dài hơn 3 ký tự, nhưng tương đương với[x for x=1:4]

5

Sử dụng các cuộc gọi chức năng Broadcasting.

Đượ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ự
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.