Cách giải quyết của Python để gán trong lambda


34

Đây là một câu hỏi mẹo để chơi gôn trong Python.

Trong chơi gôn Python, thông thường, một bài nộp là một hàm được định nghĩa là lambda. Ví dụ,

f=lambda x:0**x or x*f(x-1)

tính giai thừa của x.

Định dạng lambda có hai ưu điểm lớn :

  • Bản tóm tắt của f=lambda x:...hoặc lambda x:...ngắn hơn def f(x):...return...hoặcx=input()...print...
  • Một cuộc gọi đệ quy có thể được sử dụng để lặp với ít chi phí byte.

Tuy nhiên, lambdas có nhược điểm lớn là chỉ cho phép một biểu thức duy nhất, không có tuyên bố. Đặc biệt, điều này có nghĩa là không có bài tập như thế nào c=chr(x+65). Đây là vấn đề khi một người có một biểu thức dài mà giá trị của nó cần được tham chiếu hai lần (hoặc nhiều hơn).

Các phép gán như E=enumeratecó thể bên ngoài hàm hoặc như một đối số tùy chọn, nhưng chỉ khi chúng không phụ thuộc vào các đầu vào hàm. Các đối số tùy chọn như f=lambda n,k=min(n,0):...thất bại vì đầu vào nchưa được xác định khi kđược đánh giá tại thời điểm xác định.

Kết quả là đôi khi bạn không muốn lặp lại một biểu thức dài trong lambda bởi vì sự thay thế là một non-lambda dài.

lambda s:s.strip()+s.strip()[::-1]
def f(s):t=s.strip();print t+t[::-1]

Điểm hòa vốn là khoảng 11 ký tự ( chi tiết ), qua đó bạn chuyển sang một defhoặc program. So sánh điểm này với điểm hòa vốn thông thường có độ dài 5 cho biểu thức lặp lại:

range(a)+range(b)
r=range;r(a)+r(b)

print s[1:],s[1:]*2
r=s[1:];print r,r*2

Các ngôn ngữ khác có cách giải quyết, ví dụ như Octave . Có những thủ thuật đã biết đối với Python, nhưng chúng dài, cồng kềnh và / hoặc sử dụng hạn chế. Một phương pháp ngắn, đa mục đích để mô phỏng bài tập trong lambda sẽ cách mạng hóa việc chơi gôn Python.


Các cách để một người chơi gôn Python vượt qua hoặc khắc phục giới hạn này là gì? Những ý tưởng tiềm năng nào họ nên có trong đầu khi họ thấy một biểu hiện dài được lặp lại hai lần trong lambda?

Mục tiêu của tôi với câu hỏi mẹo này là đi sâu vào vấn đề này và:

  • Danh mục và phân tích cách giải quyết chơi golf để chuyển nhượng giả trong lambda
  • Khám phá khách hàng tiềm năng mới để có phương pháp tốt hơn

Mỗi câu trả lời nên giải thích một cách giải quyết hoặc tiềm năng.


Tôi đoán đây là một trong những điều không thể thực hiện tốt trong Python. JavaScript có một chân trên này.
mbomb007

Cũng giống như câu trả lời của orlp, gợi ý (đã xóa) của Neil về việc sử dụng lambdas lồng nhau không nhất thiết phải dài hơn def trong trường hợp bạn cần lambda lồng nhau. Tôi nghĩ rằng nó xứng đáng được phân tích kỹ lưỡng hơn.
Martin Ender

2
Đối với ví dụ chính xác được đưa ra với phép nối chuỗi ký tự viết ngược, người ta có thể thực hiện lambda s:(s+s[::-1]).lower(). Tất nhiên điều này không trả lời câu hỏi thực tế.
Jonathan Allan

@Jonathan ALLan Điểm tốt, đã đổi nó thành strip.
xnor

Câu trả lời:


6

eval

Bản thân nó không phải là tuyệt vời, nhưng nếu giải pháp của bạn đã sử dụng evaltheo một cách nào đó hoặc hình thức, bạn thường có thể sử dụng kỹ thuật này.

eval("%f*%f+%f"%((5**.5,)*3))

Wow, thật thông minh! Tại sao tôi không bao giờ thấy loại mã này?
z0rberg

6
@ z0rberg Có lẽ vì eval là ác quỷ.
HyperNeutrino

Tôi không đăng ký theo chủ nghĩa mã này. #EvalLivesMatter ... nhưng nghiêm túc, làm thế nào tệ hơn tiêm dll đơn giản?
z0rberg

6

Biểu thức chuyển nhượng trong Python 3.8

Python 3.8 ( TIO ) giới thiệu các biểu thức gán , sử dụng :=để gán một biến nội tuyến như là một phần của biểu thức.

>>> (n:=2, n+1)
(2, 3)

Điều này có thể được sử dụng trong một lambda, trong đó các bài tập không được phép thông thường. Đối chiếu:

lambda s:(t:=s.strip())+t[::-1]
lambda s:s.strip()+s.strip()[::-1]
def f(s):t=s.strip();return t+t[::-1]

Xem mẹo này để biết thêm.


2

Lambdas bên trong

Điều này cho phép bạn xác định nhiều biến cùng một lúc.

lambda s:s.strip()+s.strip()[::-1]

so với

lambda s:(lambda t:t+t[::-1])(s.strip())

dài hơn nhiều, nhưng nếu bạn có nhiều biến hoặc các biến dài hơn, được lặp lại nhiều lần:

lambda a,b,c:a.upper()*int(c)+b.lower()*int(c)+a.upper()[::-1]+b.lower()[::-1]+a.upper()*int(c)+a.lower()*int(c)

so với

lambda a,B,c:(lambda A,b,n:A*n+b*n+A[::-1]+b[::-1]+A*n+b*c)(a.upper(),B.lower(),int(c))

Số lượng nhân vật

Ban đầu: (lambda:)()(11 byte)
Biến đầu tiên: [space]a(2 byte)
Biến tiếp theo: ,b,(3 byte)
Sử dụng: a(1 byte).

(lambda* a*_,b_:)(*<value a>*_,<value b>_)

(Cũng lưu trên ngoặc)

Vì vậy, điều này có 3n + 10byte, trong đó nsố lượng biến. Đây là một chi phí ban đầu cao, nhưng cuối cùng có thể trả hết. Nó thậm chí trả về giá trị bên trong của nó, vì vậy bạn có thể lồng nhiều lần (Mặc dù điều này sẽ nhanh chóng trở nên không xứng đáng.)

Điều này thực sự chỉ hữu ích cho các tính toán trung gian dài trong việc hiểu danh sách lồng nhau, vì def f():a=...;b=...;returnthông thường sẽ ngắn hơn.

Đối với 1 giá trị, điều này tiết kiệm : uses * length - length - uses - 13, vì vậy chỉ hữu ích khi biểu thức đó là dương.
Đối với một nbiểu thức khác nhau được sử dụng utổng cộng, trong đó độ dài kết hợp của chúng là l, điều này sẽ tiết kiệm:
l - (3 * n) - u - 10 ( + brackets removed )


1

Sử dụng một danh sách

Khai báo một danh sách làm tham số và sử dụng .append() orđể lưu trữ giá trị:
lambda s:s.lower()+s.lower()[::-1]
biến thành
lambda s,l=[]:l.append(s.lower())or l[-1]+l[-1][::-1]

Số lượng nhân vật:

,l=[]5 ký tự
l.append()or13 ký tự
l[-1]5 ký tự cho mỗi lần sử dụng

Hòa vốn

Số lượng ký tự được thêm vào là:
uses*(5-length) + 18 + length
Trong ví dụ trước, câu lệnh s.lower()dài 9 ký tự và được sử dụng 2 lần, áp dụng kỹ thuật này thêm 19 ký tự. Nếu nó được sử dụng 7 lần, sẽ giảm 1 ký tự.
Số lượng sử dụng tối thiểu cho kỹ thuật này có giá trị là
min_uses = (18+length)/(length-5)

Ưu điểm

  • Cho phép một nhiệm vụ mới với chi phí giảm nhẹ (danh sách đã được khai báo)
  • Là một listđối tượng quá [0], .pop(), [x:y]và chức năng danh sách khác có thể được sử dụng cho các thủ thuật. tình huống cao

Nhược điểm

  • Chi phí ban đầu cao
  • Chi phí sử dụng cao
  • Chỉ hoạt động để sử dụng với chiều dài cao hơn 5

Sử dụng từ điển

cảm ơn @Zgarb
Ý tưởng tương tự như trên Khai báo một từ điển làm tham số và sử dụng .setdefault()để lưu trữ (và trả về) giá trị:
lambda s:s.lower()+s.lower()[::-1]
biến thành
lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]
Lưu ý rằng, không giống như listđối tác, setdefaulttrả về giá trị được gán.

Số lượng nhân vật:

,d={}5 ký tự
d.setdefault(k,)16 ký tự
d[k]4 ký tự cho mỗi lần sử dụng

Hòa vốn

Số lượng ký tự được thêm vào là:
(uses-1)*(4-length) + 21
Trong ví dụ trước, câu lệnh s.lower()dài 9 ký tự và được sử dụng 2 lần, áp dụng kỹ thuật này thêm 16 ký tự. Nếu nó được sử dụng 7 lần, sẽ giảm 1 ký tự.
Số lượng sử dụng tối thiểu cho kỹ thuật này có giá trị là
min_uses = 1-21/(4-length)

Nhược điểm / nhược điểm

  • Về cơ bản giống như danh sách
  • Chỉ hoạt động để sử dụng với chiều dài cao hơn 4

Những ý kiến ​​khác

  • Nếu kỹ thuật này có giá trị giảm ký tự, thì lambdacó lẽ có thể bỏ và hàm được viết lại bằng def/ inputcho một chương trình ngắn hơn.
  • Như @FlipTack đã chỉ ra, danh sách và lệnh chính là KEEPT giữa các lệnh gọi hàm, trong khi điều này chủ yếu sẽ làm phiền, nó có thể được sử dụng cho các cuộc gọi đệ quy. lại có tính tình huống cao
  • Từ điển sẽ luôn luôn ngắn hơn danh sách.

3
Các chức năng đệ trình phải được sử dụng nhiều lần. Hiện tại điều này sử dụng cùng một danh sách mỗi khi lambda được chạy, điều này có thể làm rối tung mọi thứ trong các lần chạy sau.
FlipTack

@FlipTack không quan tâm, bạn có phiền khi liên kết một nguồn như meta không? Tôi nghĩ rằng quy tắc đó có thể có một số tác động đến một vài thủ thuật mà tôi biết.
JAD


Tôi nghĩ bạn có thể làm tốt hơn với một từ điển: lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]Nó cũng có thể tái sử dụng.
Zgarb

Bạn có thể sử dụng list.extendđể thêm nhiều yếu tố cùng một lúc, sẽ ngắn hơn so với sử dụng list.appendnhiều lần.
mbomb007

0

Sử dụng để đặt biến và trả về dữ liệu sau khi hoạt động như sau:

add = lambda x, y: exec("x+=y")

cách khác: {add = lambda x, y: [x.append (x [0] + y), x.reverse (), x.pop ()]}
Dylan Eliot

0

Danh sách hiểu

Đây là một giải pháp cuối cùng vì nó quá vô dụng, nhưng bạn có thể làm
[<expression> for <variable> in <value>]
để đặt giả một biến trong lambda. Về cơ bản, điểm tốt duy nhất về phương pháp này là biểu hiện bên trong có thể đọc được, đây rõ ràng là điều ít quan tâm nhất của bạn khi chơi golf.

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.