วิธีการเขียนขนาดกะทัดรัด (a + b == c หรือ a + c == b หรือ b + c == a)


136

มีวิธีกะทัดรัดหรือ pythonic มากขึ้นในการเขียนนิพจน์บูลีน

a + b == c or a + c == b or b + c == a

ฉันมาด้วย

a + b + c in (2*a, 2*b, 2*c)

แต่มันแปลกไปหน่อย


16
กะทัดรัดกว่านี้ไหม? อาจ Pythonic เพิ่มเติมหรือไม่ ไม่แน่
chepner

126
ทำสิ่งที่เป็นประโยชน์แก่ตนเองในอนาคตและเก็บไว้ในรูปแบบดั้งเดิม: มันเป็นสิ่งเดียวที่บอกได้ทันทีถึงจุดประสงค์ของสิ่งนี้ อย่าแก้ไขสิ่งนั้น “ เรียบง่ายดีกว่าซับซ้อน”,“ จำนวนการอ่านได้” “ หากการนำไปปฏิบัตินั้นยากที่จะอธิบายเป็นความคิดที่ไม่ดี”
สะกิด

21
Pythonic == อ่านไม่ได้?
นาฮาร์มัน

3
@wwii พวกเขาไม่ได้เกิดร่วมกัน ดู a = 0, b = 0, c = 0;)
Honza Brabec

1
สิ่งที่ @ phresnel พูด แทนที่จะพยายาม "ทำให้ง่ายขึ้น" การแสดงออกห่อในฟังก์ชั่นที่มีชื่ออธิบาย
Cephalopod

คำตอบ:


206

ถ้าเราดูที่ Zen of Python ให้เน้นไปที่:

The Zen of Python โดย Tim Peters

สวยดีกว่าน่าเกลียด
ชัดเจนดีกว่าโดยปริยาย
เรียบง่ายดีกว่าซับซ้อน
คอมเพล็กซ์ดีกว่าซับซ้อน
แบนดีกว่าซ้อนกัน
เบาบางดีกว่าหนาแน่น
จำนวนการอ่าน
กรณีพิเศษไม่พิเศษพอที่จะทำลายกฎ
แม้ว่าการปฏิบัติจริงชนะความบริสุทธิ์
ข้อผิดพลาดไม่ควรผ่านไปอย่างเงียบ ๆ
เว้นแต่จะปิดเสียงอย่างชัดเจน
ในการเผชิญกับความกำกวมปฏิเสธสิ่งล่อใจที่จะคาดเดา
ควรมีอย่างน้อยหนึ่งวิธีที่ชัดเจนกว่าที่จะทำ
แม้ว่าวิธีนี้อาจไม่ชัดเจนในตอนแรกเว้นแต่ว่าคุณเป็นชาวดัตช์
ตอนนี้ดีกว่าไม่เคย
แม้ว่าจะไม่เคยดีกว่าที่เหมาะสมในขณะนี้
หากการนำไปปฏิบัตินั้นยากที่จะอธิบายเป็นความคิดที่ไม่ดี
หากการนำไปปฏิบัตินั้นง่ายต่อการอธิบายอาจเป็นความคิดที่ดี
Namespaces เป็นหนึ่งในแนวคิดที่ยอดเยี่ยม - ลองทำสิ่งเหล่านี้ให้มากขึ้น!

วิธีการแก้ปัญหา Pythonic ที่มากที่สุดคือคำที่ชัดเจนง่ายที่สุดและง่ายที่สุดในการอธิบาย:

a + b == c or a + c == b or b + c == a

ยิ่งไปกว่านั้นคุณไม่จำเป็นต้องรู้จัก Python เพื่อทำความเข้าใจกับรหัสนี้! มันเป็นเรื่องที่ง่าย นี่คือทางออกที่ดีที่สุดโดยไม่ต้องจอง สิ่งอื่นใดก็คือการสำเร็จความใคร่ด้วยตนเอง

นอกจากนี้ยังเป็นทางออกที่มีประสิทธิภาพที่ดีที่สุดเช่นกันเนื่องจากเป็นข้อเสนอเพียงข้อเดียวที่ลัดวงจร หากa + b == cมีการเพิ่มและเปรียบเทียบเพียงครั้งเดียวเท่านั้น


11
ยิ่งไปกว่านั้นให้ใส่วงเล็บบางอันไว้เพื่อทำให้เจตนาชัดเจน
ไบรอัน Oakley

3
ความตั้งใจชัดเจนแล้วโดยไม่ต้องวงเล็บ วงเล็บจะทำให้อ่านยากขึ้น - เหตุใดผู้เขียนจึงใช้วงเล็บเมื่อลำดับความสำคัญนี้ครอบคลุมอยู่แล้ว
เส้นทาง Miles Rout

1
หมายเหตุอื่น ๆ เกี่ยวกับการพยายามฉลาดเกินไป: คุณอาจแนะนำข้อผิดพลาดที่ไม่คาดคิดโดยไม่มีเงื่อนไขที่คุณไม่ได้พิจารณา กล่าวอีกนัยหนึ่งคุณอาจคิดว่าโซลูชันขนาดกะทัดรัดใหม่ของคุณนั้นเทียบเท่า แต่ไม่ได้มีในทุกกรณี เว้นแต่จะมีเหตุผลที่น่าสนใจในการเขียนโค้ดเป็นอย่างอื่น (ประสิทธิภาพข้อ จำกัด หน่วยความจำและอื่น ๆ ) ความคมชัดคือราชา
Rob Craig

มันขึ้นอยู่กับว่าสูตรนั้นมีไว้สำหรับอะไร ดู 'ชัดเจนกว่าดีกว่านัย' อาจเป็นได้ว่า 'การเรียงลำดับแรก' เป็นวิธีที่ชัดเจนมากขึ้นแสดงว่าโปรแกรมกำลังทำอะไรอยู่หรืออย่างใดอย่างหนึ่ง ฉันไม่คิดว่าเราจะตัดสินจากคำถามได้
โทมัส Ahle

101

การแก้ความเท่าเทียมกันทั้งสามสำหรับ:

a in (b+c, b-c, c-b)

4
ปัญหาเดียวของเรื่องนี้คือผลข้างเคียง หาก b หรือ c เป็นนิพจน์ที่ซับซ้อนกว่าพวกเขาจะทำงานหลายครั้ง
Silvio Mayolo

3
@ Kroltan จุดของฉันคือการที่ฉันตอบคำถามของเขาซึ่งถามหาตัวแทน "กระชับมากขึ้น" ดู: en.m.wikipedia.org/wiki/Short-circuit_evaluation
Alex Varga

24
ใครก็ตามที่อ่านรหัสนี้อาจจะสาปแช่งคุณเพราะ "ฉลาด"
Karoly Horvath

5
@SilvioMayolo เช่นเดียวกับของจริง
Izkata

1
@AlexVarga "ประเด็นของฉันคือการที่ฉันตอบคำถามของเขาจริง ๆ " คุณทำ; มันใช้อักขระน้อยลง 30% (การเว้นวรรคระหว่างตัวดำเนินการ) ฉันไม่ได้พยายามที่จะบอกว่าคำตอบของคุณไม่ถูกต้องเพียงแค่แสดงความคิดเห็นว่าสำนวนนั้นเป็นอย่างไร คำตอบที่ดี
พอลเดรเปอร์

54

Python มีanyฟังก์ชั่นที่ทำหน้าที่orเกี่ยวกับองค์ประกอบทั้งหมดของลำดับ ที่นี่ฉันได้แปลงคำสั่งของคุณเป็น tuple 3 องค์ประกอบ

any((a + b == c, a + c == b, b + c == a))

โปรดทราบว่าการorลัดวงจรดังนั้นหากการคำนวณเงื่อนไขแต่ละรายการมีราคาแพงมันอาจจะดีกว่าที่จะรักษาโครงสร้างเดิมของคุณ


2
any()และall()ลัดวงจรด้วย
TigerhawkT3

42
@ TigerhawkT3 ไม่ใช่ในกรณีนี้ นิพจน์ทั้งสามจะได้รับการประเมินก่อนที่จะมี tuple และ tuple จะมีอยู่ก่อนที่anyจะรัน
สะกิด

13
อ่าฉันเข้าใจแล้ว ฉันเดาว่ามันจะเกิดขึ้นก็ต่อเมื่อมีเครื่องกำเนิดไฟฟ้าหรือตัววนซ้ำแบบขี้เกียจอยู่ในนั้น
TigerhawkT3

4
anyและall"การลัดวงจร" กระบวนการตรวจสอบการทำซ้ำที่พวกเขาได้รับ แต่ถ้าว่า iterable เป็นลำดับมากกว่าเครื่องกำเนิดไฟฟ้าแล้วมันมีอยู่แล้วได้รับการประเมินอย่างเต็มที่ก่อนที่จะเรียกฟังก์ชั่นเกิดขึ้น
Karl Knechtel

สิ่งนี้มีข้อดีที่ง่ายต่อการแยกหลายบรรทัด (การเยื้องอาร์กิวเมนต์ไปที่anyการเยื้องเดียว):ในifคำสั่ง) ซึ่งจะช่วยให้สามารถอ่านได้ง่ายเมื่อคณิตศาสตร์มีส่วนร่วม
Izkata

40

หากคุณรู้ว่าคุณต้องติดต่อกับตัวเลขที่เป็นบวกเท่านั้นสิ่งนี้จะใช้ได้และค่อนข้างสะอาด:

a, b, c = sorted((a, b, c))
if a + b == c:
    do_stuff()

อย่างที่ฉันพูดไปมันใช้งานได้กับจำนวนบวกเท่านั้น แต่ถ้าคุณรู้ว่ามันจะเป็นค่าบวกนี่เป็นทางออกที่ IMO อ่านได้ง่ายมากแม้กระทั่งในรหัสโดยตรงเมื่อเทียบกับฟังก์ชั่น

คุณสามารถทำสิ่งนี้ได้ซึ่งอาจทำการคำนวณซ้ำหลายครั้ง แต่คุณไม่ได้ระบุประสิทธิภาพเป็นเป้าหมายของคุณ:

from itertools import permutations

if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
    do_stuff()

หรือไม่มีpermutations()และความเป็นไปได้ของการคำนวณซ้ำ:

if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
    do_stuff()

ฉันอาจจะใส่นี่หรือวิธีแก้ปัญหาอื่น ๆ ในฟังก์ชั่น จากนั้นคุณสามารถเรียกฟังก์ชันในโค้ดของคุณได้อย่างหมดจด

โดยส่วนตัวถ้าฉันต้องการความยืดหยุ่นมากขึ้นจากรหัสฉันจะใช้วิธีแรกในคำถามของคุณ มันง่ายและมีประสิทธิภาพ ฉันยังอาจใส่ลงในฟังก์ชั่น:

def two_add_to_third(a, b, c):
    return a + b == c or a + c == b or b + c == a

if two_add_to_third(a, b, c):
    do_stuff()

นั่นเป็น Pythonic ที่น่ารักและมันก็เป็นวิธีที่มีประสิทธิภาพมากที่สุดในการทำมัน แม้ว่าคุณไม่ควรกังวลเกี่ยวกับประสิทธิภาพมากนักเว้นแต่ว่ามันจะทำให้เกิดปัญหา


โดยเฉพาะอย่างยิ่งถ้าเราสามารถสันนิษฐานได้ว่า a, b, c ล้วน แต่ไม่ใช่เชิงลบ
cphlewis

ฉันพบว่าวลี "ไม่ได้ผลเสมอไป" ทำให้เกิดความสับสนเล็กน้อย วิธีแก้ปัญหาแรกจะทำงานได้ก็ต่อเมื่อคุณทราบว่าหมายเลขของคุณไม่เป็นลบ ตัวอย่างเช่นด้วย (a, b, c) = (-3, -2, -1) คุณมี + b! = c แต่ b + c = a กรณีที่คล้ายกันกับ (-1, 1, 2) และ (-2, -1, 1)
หมายเลขผู้ใช้

@usernumber คุณรู้ว่าฉันสังเกตเห็นว่าก่อนหน้านี้; ไม่แน่ใจว่าทำไมฉันไม่แก้ไข
Cyphase

โซลูชันอันดับต้น ๆ ของคุณไม่ทำงานสำหรับอินพุตที่มีขนาดใหญ่ในขณะที่ข้อเสนอแนะของ OP ใช้งานได้กับอินพุตทั้งหมด "ไม่ทำงาน" Pythonic มากกว่า "ทำงาน" ได้อย่างไร
Barry

3
โอ้โห " ถ้าคุณรู้ว่าคุณกำลังติดต่อกับตัวเลขที่เป็นบวกสิ่งนี้จะใช้ได้และค่อนข้างสะอาด" ส่วนที่เหลือทั้งหมดทำงานกับตัวเลขใด ๆ แต่ถ้าคุณรู้ว่าคุณกำลังติดต่อกับตัวเลขที่เป็นบวกเท่านั้นอันดับหนึ่งนั้นสามารถอ่านได้ / Pythonic IMO
Cyphase

17

หากคุณจะใช้เพียงสามตัวแปรแล้ววิธีการเริ่มต้นของคุณ:

a + b == c or a + c == b or b + c == a

มีความไพเราะมากแล้ว

หากคุณวางแผนที่จะใช้ตัวแปรเพิ่มเติมวิธีการให้เหตุผลของคุณด้วย:

a + b + c in (2*a, 2*b, 2*c)

ฉลาดมาก แต่ให้คิดว่าทำไม ทำไมจึงใช้งานได้
จากการคำนวณทางคณิตศาสตร์อย่างง่ายเราเห็นว่า:

a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c

และสิ่งนี้จะต้องถือเป็นจริงสำหรับทั้ง A, B, C หรือความหมายใช่ว่ามันจะเท่ากับ2*a, หรือ2*b 2*cสิ่งนี้จะเป็นจริงสำหรับตัวแปรจำนวนเท่าใดก็ได้

วิธีที่ดีในการเขียนสิ่งนี้อย่างรวดเร็วก็คือการมีรายการตัวแปรของคุณและตรวจสอบผลรวมกับรายการค่าสองเท่า

values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])

วิธีนี้หากต้องการเพิ่มตัวแปรเพิ่มเติมลงในสมการสิ่งที่คุณต้องทำคือแก้ไขรายการค่าของคุณด้วยตัวแปรใหม่ 'n' ไม่ใช่เขียนสมการ 'n'


4
สิ่งที่เกี่ยวกับa=-1, b=-1, c=-2แล้วa+b=cแต่a+b+c = -4และ2*max(a,b,c)เป็น-2
เอริค Renouf

ขอบคุณที่เป็นจริงฉันจะต้องใช้ abs ทำการปรับเปลี่ยนทันที
ThatGuyRussell

2
หลังจากที่โทรมาด้วยครึ่งโหลabs()มันเป็น Pythonic มากกว่าตัวอย่างของ OP (จริง ๆ แล้วฉันเรียกมันว่าอ่านไม่ได้)
TigerhawkT3

นั่นเป็นความจริงอย่างมากฉันจะปรับเปลี่ยนทันที
ThatGuyRussell

1
@ThatGuyRussell ในการลัดวงจรคุณต้องการใช้เครื่องกำเนิดไฟฟ้า ... แบบany(sum(values) == 2*x for x in values)ที่คุณไม่ต้องทำทุกอย่างขึ้นด้านหน้าเท่าที่จำเป็น
Barry

12

รหัสต่อไปนี้สามารถใช้ในการเปรียบเทียบแต่ละองค์ประกอบซ้ำกับผลรวมขององค์ประกอบอื่น ๆ ซึ่งคำนวณจากผลรวมของรายการทั้งหมดยกเว้นองค์ประกอบนั้น

 l = [a,b,c]
 any(sum(l)-e == e for e in l)

2
ดี :) ฉันคิดว่าถ้าคุณลบ[]วงเล็บออกจากบรรทัดที่สองนี่จะทำให้เกิดการลัดวงจรเหมือนต้นฉบับด้วยor...
psmears

1
ซึ่งโดยทั่วไปany(a + b + c == 2*x for x in [a, b, c])แล้วค่อนข้างใกล้กับคำแนะนำของ OP
njzk2

ที่คล้ายกันอย่างไรก็ตามวิธีนี้ขยายไปถึงจำนวนของตัวแปรใด ๆ ฉันรวมข้อเสนอแนะโดย @psmears เกี่ยวกับการลัดวงจร
Arcanum

10

อย่าพยายามทำให้มันง่ายขึ้น ให้ตั้งชื่อสิ่งที่คุณทำด้วยฟังก์ชั่นแทน:

def any_two_sum_to_third(a, b, c):
  return a + b == c or a + c == b or b + c == a

if any_two_sum_to_third(foo, bar, baz):
  ...

แทนที่เงื่อนไขด้วยสิ่งที่ "ฉลาด" อาจทำให้สั้นลง แต่จะไม่ทำให้อ่านง่ายขึ้น ปล่อยให้มันไม่สามารถอ่านได้มากเช่นกันเพราะมันเป็นเรื่องยากที่จะรู้ว่าทำไมคุณกำลังตรวจสอบสามเงื่อนไขอย่างรวดเร็ว สิ่งนี้ทำให้ชัดเจนอย่างยิ่งกับสิ่งที่คุณกำลังตรวจสอบ

เกี่ยวกับประสิทธิภาพวิธีการนี้จะเพิ่มโอเวอร์เฮดของการเรียกใช้ฟังก์ชัน แต่ไม่เคยเสียสละความสามารถในการอ่านสำหรับประสิทธิภาพเว้นแต่คุณจะพบปัญหาคอขวดที่คุณต้องแก้ไข และวัดทุกครั้งเนื่องจากการใช้งานที่ชาญฉลาดบางอย่างสามารถปรับให้เหมาะสมและอินไลน์การเรียกใช้ฟังก์ชันบางอย่างในบางสถานการณ์


1
ควรเขียนฟังก์ชั่นเฉพาะในกรณีที่คุณคาดว่าจะใช้รหัสเดียวกันมากกว่าหนึ่งจุดหรือหากรหัสนั้นซับซ้อน ไม่มีการกล่าวถึงการใช้รหัสซ้ำในคำถามเดิมและการเขียนฟังก์ชั่นสำหรับรหัสบรรทัดเดียวนั้นไม่เพียง แต่เกินความจริง แต่จริงๆแล้วมันทำให้การอ่านไม่ได้
Igor Levicki

5
มาจากโรงเรียน FP ของสิ่งต่าง ๆ ฉันแทบจะไม่เห็นด้วยอย่างสมบูรณ์และระบุว่าฟังก์ชั่นหนึ่งบรรทัดเป็นเครื่องมือที่ดีที่สุดในการเพิ่มความสามารถในการอ่านที่คุณจะพบ สร้างฟังก์ชั่นเมื่อใดก็ตามที่ขั้นตอนที่คุณกำลังทำบางสิ่งไม่ได้ทำให้เกิดความชัดเจนทันทีในสิ่งที่คุณทำเพราะชื่อของฟังก์ชั่นช่วยให้คุณระบุสิ่งที่ดีกว่าความคิดเห็นใด ๆ
แจ็ค

ไม่ว่าโรงเรียนใดที่คุณเรียกใช้จะเป็นการดีที่จะไม่ปฏิบัติตามกฎเกณฑ์ ต้องข้ามไปยังส่วนอื่นของแหล่งที่มาเพื่ออ่านรหัสหนึ่งบรรทัดที่ซ่อนอยู่ภายในฟังก์ชั่นเพื่อให้สามารถตรวจสอบว่าจริง ๆ แล้วมันทำในสิ่งที่มันพูดในชื่อแล้วต้องเปลี่ยนกลับไปยังสถานที่โทร ตรวจสอบให้แน่ใจว่าคุณผ่านพารามิเตอร์ที่ถูกต้องคือการสลับบริบทที่ไม่จำเป็นทั้งหมด ในความคิดของฉันการทำที่บั่นทอนทั้งการอ่านและเวิร์กโฟลว์ ในที่สุดทั้งชื่อของฟังก์ชั่นและความคิดเห็นของรหัสจะถูกแทนที่ที่เหมาะสมสำหรับเอกสารรหัส
Igor Levicki

9

Python 3:

(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...

มันปรับขนาดเป็นตัวแปรจำนวนเท่าใดก็ได้:

arr = [a,b,c,d,...]
sum(arr)/2 in arr

อย่างไรก็ตามโดยทั่วไปฉันยอมรับว่าหากคุณไม่มีตัวแปรมากกว่าสามตัวเวอร์ชันดั้งเดิมจะสามารถอ่านได้มากขึ้น


3
สิ่งนี้ส่งคืนผลลัพธ์ที่ไม่ถูกต้องสำหรับอินพุตบางอันเนื่องจากข้อผิดพลาดในการปัดเศษทศนิยม
pts

ควรหลีกเลี่ยงการหารด้วยเหตุผลด้านประสิทธิภาพและความแม่นยำ
Igor Levicki

1
@pts การใช้งานใด ๆ จะไม่ส่งคืนผลลัพธ์ที่ไม่ถูกต้องเนื่องจากมีการปัดเศษทศนิยม แม้แต่ a + b == c
osundblad

@osundblad: หาก a, b และ c เป็น ints ดังนั้น (a + b + c) / 2 ทำการปัดเศษ (และอาจส่งกลับผลลัพธ์ที่ไม่ถูกต้อง) แต่ a + b == c นั้นถูกต้อง
pts

3
หารด้วย 2 เป็นเพียงการลดลงเลขชี้กำลังโดยหนึ่งจึงจะมีความถูกต้องสำหรับจำนวนเต็มใด ๆ ที่น้อยกว่า 2 ^ 53 (ส่วนส่วนของลอยในหลาม) และสำหรับจำนวนเต็มขนาดใหญ่คุณสามารถใช้ทศนิยม ตัวอย่างเช่นหากต้องการตรวจสอบจำนวนเต็มที่น้อยกว่า 2 ^ 30 ทำงาน[x for x in range(pow(2,30)) if x != ((x * 2)/ pow(2,1))]
Vitalii Fedorenko

6
(a+b-c)*(a+c-b)*(b+c-a) == 0

หากผลรวมของสองเทอมใด ๆ เท่ากับเทอมที่สามดังนั้นหนึ่งในปัจจัยจะเป็นศูนย์ทำให้ผลิตภัณฑ์ทั้งหมดเป็นศูนย์


ฉันคิดอย่างเดียวกัน แต่ฉันไม่สามารถปฏิเสธได้ว่าข้อเสนอดั้งเดิมของเขานั้นช่างดูสะอาดกว่าเดิม ...
user541686

@ Mehrdad - แน่นอน จริงๆมันไม่แตกต่าง(a+b<>c) && (a+c<>b) && (b+c<>a) == false
mbeckish

มันเป็นเพียงการคูณที่มีราคาแพงกว่าการแสดงออกตรรกะและเลขคณิตพื้นฐาน
Igor Levicki

@IgorLevicki - ใช่แม้ว่าจะเป็นปัญหาการเพิ่มประสิทธิภาพก่อนวัยอันควร นี่จะมีการแสดงเป็นหมื่นครั้งต่อวินาทีหรือไม่ ถ้าใช่คุณอาจต้องการดูอย่างอื่น
mbeckish

@mbeckish - ทำไมคุณถึงคิดว่ามันคลอดก่อนกำหนด? ควรเขียนโค้ดด้วยการเพิ่มประสิทธิภาพในใจไม่ได้รับการปรับให้เหมาะสมที่สุด วันหนึ่งนักศึกษาฝึกงานบางคนจะคัดลอกโค้ดนี้และวางลงในลูปวิกฤติที่มีประสิทธิภาพบนแพลตฟอร์มแบบฝังซึ่งจะทำงานบนอุปกรณ์หลายล้านเครื่องไม่จำเป็นต้องช้าสำหรับสิ่งที่ทำ แต่อาจเสียพลังงานแบตเตอรี่มากกว่า การเขียนรหัสดังกล่าวเป็นเพียงการส่งเสริมการเขียนโค้ดที่ไม่ดี ในความคิดของฉันสิ่งที่ OP ควรถามคือมีวิธีเพิ่มประสิทธิภาพการแสดงออกของตรรกะนั้นหรือไม่
Igor Levicki

6

เพียงแค่:

a == b + c or abs(a) == abs(b - c)

โปรดทราบว่าสิ่งนี้จะไม่ทำงานหากตัวแปรไม่ได้ลงนาม

จากมุมมองของการเพิ่มประสิทธิภาพโค้ด (อย่างน้อยบนแพลตฟอร์ม x86) นี่น่าจะเป็นทางออกที่มีประสิทธิภาพที่สุด

คอมไพเลอร์ที่ทันสมัยจะ inline ทั้งเอบีเอส () ฟังก์ชั่นการโทรและการทดสอบสัญญาณหลีกเลี่ยงและสาขาเงื่อนไขที่ตามมาโดยใช้ลำดับฉลาดของ CDQ, แฮคเกอร์และคำแนะนำ รหัสระดับสูงด้านบนจะแสดงด้วยคำสั่ง ALU ที่มีความหน่วงแฝงต่ำและให้ปริมาณงานสูงเท่านั้นและเพียงสองเงื่อนไขเท่านั้น


และฉันคิดว่าfabs()สามารถใช้สำหรับfloatประเภท;)
shA.t

4

โซลูชันของ Alex Varga "a in (b + c, bc, cb)" มีขนาดกะทัดรัดและสวยงามทางคณิตศาสตร์ แต่ฉันจะไม่เขียนโค้ดแบบนั้นเพราะนักพัฒนารายต่อไปจะไม่เข้าใจวัตถุประสงค์ของโค้ดในทันที .

วิธีแก้ปัญหาของ Mark Ransom ของ

any((a + b == c, a + c == b, b + c == a))

ชัดเจนกว่า แต่ไม่รวบรัดมากกว่า

a + b == c or a + c == b or b + c == a

เมื่อเขียนโค้ดที่คนอื่นจะต้องดูหรือฉันจะต้องดูอีกนานในภายหลังเมื่อฉันลืมสิ่งที่ฉันคิดเมื่อฉันเขียนมันสั้นหรือฉลาดเกินไปที่จะทำอันตรายมากกว่าดี รหัสควรอ่านได้ รวบรัดเป็นสิ่งที่ดี แต่ไม่ย่อท้อที่โปรแกรมเมอร์รายต่อไปไม่สามารถเข้าใจได้


คำถามที่ซื่อสัตย์: ทำไมผู้คนมักคิดว่าโปรแกรมเมอร์คนต่อไปจะเป็นคนงี่เง่าที่ไม่สามารถอ่านรหัสได้? โดยส่วนตัวแล้วฉันพบว่าความคิดที่ดูถูก หากต้องเขียนโค้ดให้ชัดเจนสำหรับโปรแกรมเมอร์ทุกคนอย่างโจ่งแจ้งนั่นก็หมายความว่าเราในฐานะนักวิชาชีพนั้นมีส่วนร่วมกับตัวส่วนร่วมที่ต่ำที่สุดซึ่งเป็นทักษะที่น้อยที่สุดในหมู่พวกเรา หากเราทำเช่นนั้นพวกเขาจะพัฒนาทักษะส่วนตัวของพวกเขาอย่างไร ฉันไม่เห็นสิ่งนี้ในอาชีพอื่น ครั้งสุดท้ายที่คุณเห็นนักแต่งเพลงเขียนคะแนนดนตรีง่าย ๆ เพื่อให้นักดนตรีทุกคนสามารถเล่นได้โดยไม่ต้องคำนึงถึงระดับความสามารถ?
Igor Levicki

6
ปัญหาก็คือแม้โปรแกรมเมอร์จะมีพลังงานจิต จำกัด ดังนั้นคุณต้องการใช้พลังงานจิตที่มีอยู่อย่าง จำกัด ในอัลกอริธึมและระดับที่สูงขึ้นของโปรแกรมหรือการหาว่าบรรทัดที่ซับซ้อนของรหัสหมายความว่าเมื่อใดที่สามารถแสดงได้ง่ายขึ้น ? การเขียนโปรแกรมเป็นเรื่องยากดังนั้นอย่าทำให้ยากขึ้นสำหรับตัวคุณเองโดยไม่จำเป็นเช่นเดียวกับนักวิ่งโอลิมปิกที่จะไม่วิ่งแข่งกับกระเป๋าเป้หนัก ๆ เพราะพวกเขาทำได้ ดังที่ Steve McConell กล่าวไว้ใน Code Complete 2 ความสามารถในการอ่านเป็นหนึ่งในส่วนที่สำคัญที่สุดของโค้ด
Paul J Abernathy

2

คำขอมีขนาดกะทัดรัดมากขึ้นหรือ pythonic เพิ่มเติม - ฉันลองใช้มือของฉันอย่างกระชับ

รับ

import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
    return x + y == z

นี่คือ 2 ตัวอักษรน้อยกว่าเดิม

any(g(*args) for args in f((a,b,c)))

ทดสอบกับ:

assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)

นอกจากนี้ที่ได้รับ:

h = functools.partial(itertools.starmap, g)

สิ่งนี้เทียบเท่า

any(h(f((a,b,c))))

มันสั้นกว่าตัวละครสองตัว แต่ไม่ใช่ OP ที่ให้หลังจากนั้นซึ่งเขาบอกว่าเขากำลังใช้อยู่ ต้นฉบับยังมีพื้นที่ว่างจำนวนมากซึ่งสิ่งนี้จะละเว้นเมื่อทำได้ นอกจากนี้ยังมีเรื่องเล็ก ๆ ของฟังก์ชั่นที่g()คุณต้องกำหนดเพื่อให้ทำงานได้ จากทั้งหมดนั้นฉันจะบอกว่ามันใหญ่กว่ามาก
TigerhawkT3

@ TigerhawkT3 ฉันตีความว่ามันเป็นคำขอสำหรับนิพจน์ / บรรทัดที่สั้นกว่า เห็นการแก้ไขเพิ่มเติมสำหรับการปรับปรุง
สงครามโลกครั้งที่

4
ชื่อฟังก์ชั่นที่แย่มาก ๆ เหมาะสำหรับโค้ดกอล์ฟเท่านั้น
0xc0de

@ 0xc0de - ขอโทษที่ฉันไม่ได้เล่น เหมาะสมอาจเป็นอัตนัยและขึ้นอยู่กับสถานการณ์ - แต่ฉันจะเลื่อนไปยังชุมชน
สงครามโลกครั้งที่

ฉันไม่เห็นว่าขนาดนี้จะกระชับได้อย่างไรเมื่อมีอักขระมากกว่ารหัสต้นฉบับ
Igor Levicki

1

ฉันต้องการนำเสนอสิ่งที่ฉันเห็นว่าเป็นคำตอบที่ไพเราะที่สุด:

def one_number_is_the_sum_of_the_others(a, b, c):
    return any((a == b + c, b == a + c, c == a + b))

กรณีทั่วไปไม่เหมาะ:

def one_number_is_the_sum_of_the_others(numbers):
    for idx in range(len(numbers)):
        remaining_numbers = numbers[:]
        sum_candidate = remaining_numbers.pop(idx)
        if sum_candidate == sum(remaining_numbers):
            return True
    return False 

ในแง่ของ Zen of Python ฉันคิดว่าข้อความที่ถูกเน้นนั้นมีการติดตามมากกว่าคำตอบอื่น ๆ :

The Zen of Python โดย Tim Peters

สวยดีกว่าน่าเกลียด
ชัดเจนดีกว่าโดยปริยาย
เรียบง่ายดีกว่าซับซ้อน
คอมเพล็กซ์ดีกว่าซับซ้อน
แบนดีกว่าซ้อนกัน
เบาบางดีกว่าหนาแน่น
จำนวนการอ่าน
กรณีพิเศษไม่พิเศษพอที่จะทำลายกฎ
แม้ว่าการปฏิบัติจริงชนะความบริสุทธิ์
ข้อผิดพลาดไม่ควรผ่านไปอย่างเงียบ ๆ
เว้นแต่จะปิดเสียงอย่างชัดเจน
ในการเผชิญกับความกำกวมปฏิเสธสิ่งล่อใจที่จะคาดเดา
ควรมีอย่างน้อยหนึ่งวิธีที่ชัดเจนกว่าที่จะทำ
แม้ว่าวิธีนี้อาจไม่ชัดเจนในตอนแรกเว้นแต่ว่าคุณเป็นชาวดัตช์
ตอนนี้ดีกว่าไม่เคย ที่เหมาะสมในขณะนี้
แม้ว่าจะไม่เคยดีกว่า
หากการนำไปปฏิบัตินั้นยากที่จะอธิบายเป็นความคิดที่ไม่ดี
หากการนำไปปฏิบัตินั้นง่ายต่อการอธิบายอาจเป็นความคิดที่ดี
Namespaces เป็นหนึ่งในแนวคิดที่ยอดเยี่ยม - ลองทำสิ่งเหล่านี้ให้มากขึ้น!


1

ในฐานะที่เป็นนิสัยเก่าแก่ของการเขียนโปรแกรมของฉันฉันคิดว่าการวางนิพจน์ที่ซับซ้อนทางด้านขวาในประโยคสามารถทำให้อ่านง่ายขึ้นเช่นนี้

a == b+c or b == a+c or c == a+b

บวก():

((a == b+c) or (b == a+c) or (c == a+b))

และฉันก็คิดว่าการใช้หลายบรรทัดนั้นสามารถสร้างความรู้สึกได้มากกว่านี้:

((a == b+c) or 
 (b == a+c) or 
 (c == a+b))

0

ด้วยวิธีทั่วไป

m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();

ถ้าการจัดการตัวแปรอินพุตนั้นใช้ได้สำหรับคุณ

c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();

หากคุณต้องการใช้ช่องโหว่บิตคุณสามารถใช้ "!", ">> 1" และ "<< 1"

ฉันหลีกเลี่ยงการแบ่งแม้ว่ามันจะช่วยให้ใช้เพื่อหลีกเลี่ยงการคูณสองเพื่อหลีกเลี่ยงข้อผิดพลาดปัดเศษ อย่างไรก็ตามตรวจสอบโอเวอร์โฟลว์


0
def any_sum_of_others (*nums):
    num_elements = len(nums)
    for i in range(num_elements):
        discriminating_map = map(lambda j: -1 if j == i else 1, range(num_elements))
        if sum(n * u for n, u in zip(nums, discriminating_map)) == 0:
            return True
    return False

print(any_sum_of_others(0, 0, 0)) # True
print(any_sum_of_others(1, 2, 3)) # True
print(any_sum_of_others(7, 12, 5)) # True
print(any_sum_of_others(4, 2, 2)) # True
print(any_sum_of_others(1, -1, 0)) # True
print(any_sum_of_others(9, 8, -4)) # False
print(any_sum_of_others(4, 3, 2)) # False
print(any_sum_of_others(1, 1, 1, 1, 4)) # True
print(any_sum_of_others(0)) # True
print(any_sum_of_others(1)) # False

ควรเขียนฟังก์ชั่นเฉพาะในกรณีที่คุณคาดว่าจะใช้รหัสเดียวกันมากกว่าหนึ่งจุดหรือหากรหัสนั้นซับซ้อน ไม่มีการกล่าวถึงการใช้รหัสซ้ำในคำถามเดิมและการเขียนฟังก์ชั่นสำหรับรหัสบรรทัดเดียวนั้นไม่เพียง แต่เกินความจริง แต่จริงๆแล้วมันทำให้การอ่านไม่ได้
Igor Levicki

ฉันไม่เห็นด้วยว่ามันบั่นทอนการอ่าน; หากคุณเลือกชื่อที่เหมาะสมอาจช่วยให้อ่านง่ายขึ้น (แต่ฉันไม่ได้เป็นตัวแทนเกี่ยวกับคุณภาพของชื่อที่ฉันเลือกในคำตอบนี้) นอกจากนี้ยังมีประโยชน์ในการตั้งชื่อให้กับแนวคิดซึ่งคุณจะต้องทำตราบใดที่คุณบังคับตัวเองให้ตั้งชื่อที่ดีในการทำงานของคุณ ฟังก์ชั่นเป็นสิ่งที่ดี สำหรับฟังก์ชั่นว่ามีความซับซ้อนเพียงพอที่จะได้รับประโยชน์จากการถูกห่อหุ้มในฟังก์ชั่นหรือไม่นั่นเป็นการตัดสินใจเชิงอัตวิสัย
Hammerite
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.