มีวิธีกะทัดรัดหรือ pythonic มากขึ้นในการเขียนนิพจน์บูลีน
a + b == c or a + c == b or b + c == a
ฉันมาด้วย
a + b + c in (2*a, 2*b, 2*c)
แต่มันแปลกไปหน่อย
มีวิธีกะทัดรัดหรือ pythonic มากขึ้นในการเขียนนิพจน์บูลีน
a + b == c or a + c == b or b + c == a
ฉันมาด้วย
a + b + c in (2*a, 2*b, 2*c)
แต่มันแปลกไปหน่อย
คำตอบ:
ถ้าเราดูที่ 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
มีการเพิ่มและเปรียบเทียบเพียงครั้งเดียวเท่านั้น
การแก้ความเท่าเทียมกันทั้งสามสำหรับ:
a in (b+c, b-c, c-b)
Python มีany
ฟังก์ชั่นที่ทำหน้าที่or
เกี่ยวกับองค์ประกอบทั้งหมดของลำดับ ที่นี่ฉันได้แปลงคำสั่งของคุณเป็น tuple 3 องค์ประกอบ
any((a + b == c, a + c == b, b + c == a))
โปรดทราบว่าการor
ลัดวงจรดังนั้นหากการคำนวณเงื่อนไขแต่ละรายการมีราคาแพงมันอาจจะดีกว่าที่จะรักษาโครงสร้างเดิมของคุณ
any()
และall()
ลัดวงจรด้วย
any
จะรัน
any
และall
"การลัดวงจร" กระบวนการตรวจสอบการทำซ้ำที่พวกเขาได้รับ แต่ถ้าว่า iterable เป็นลำดับมากกว่าเครื่องกำเนิดไฟฟ้าแล้วมันมีอยู่แล้วได้รับการประเมินอย่างเต็มที่ก่อนที่จะเรียกฟังก์ชั่นเกิดขึ้น
any
การเยื้องเดียว):
ในif
คำสั่ง) ซึ่งจะช่วยให้สามารถอ่านได้ง่ายเมื่อคณิตศาสตร์มีส่วนร่วม
หากคุณรู้ว่าคุณต้องติดต่อกับตัวเลขที่เป็นบวกเท่านั้นสิ่งนี้จะใช้ได้และค่อนข้างสะอาด:
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 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'
a=-1
, b=-1
, c=-2
แล้วa+b=c
แต่a+b+c = -4
และ2*max(a,b,c)
เป็น-2
abs()
มันเป็น Pythonic มากกว่าตัวอย่างของ OP (จริง ๆ แล้วฉันเรียกมันว่าอ่านไม่ได้)
any(sum(values) == 2*x for x in values)
ที่คุณไม่ต้องทำทุกอย่างขึ้นด้านหน้าเท่าที่จำเป็น
รหัสต่อไปนี้สามารถใช้ในการเปรียบเทียบแต่ละองค์ประกอบซ้ำกับผลรวมขององค์ประกอบอื่น ๆ ซึ่งคำนวณจากผลรวมของรายการทั้งหมดยกเว้นองค์ประกอบนั้น
l = [a,b,c]
any(sum(l)-e == e for e in l)
[]
วงเล็บออกจากบรรทัดที่สองนี่จะทำให้เกิดการลัดวงจรเหมือนต้นฉบับด้วยor
...
any(a + b + c == 2*x for x in [a, b, c])
แล้วค่อนข้างใกล้กับคำแนะนำของ OP
อย่าพยายามทำให้มันง่ายขึ้น ให้ตั้งชื่อสิ่งที่คุณทำด้วยฟังก์ชั่นแทน:
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):
...
แทนที่เงื่อนไขด้วยสิ่งที่ "ฉลาด" อาจทำให้สั้นลง แต่จะไม่ทำให้อ่านง่ายขึ้น ปล่อยให้มันไม่สามารถอ่านได้มากเช่นกันเพราะมันเป็นเรื่องยากที่จะรู้ว่าทำไมคุณกำลังตรวจสอบสามเงื่อนไขอย่างรวดเร็ว สิ่งนี้ทำให้ชัดเจนอย่างยิ่งกับสิ่งที่คุณกำลังตรวจสอบ
เกี่ยวกับประสิทธิภาพวิธีการนี้จะเพิ่มโอเวอร์เฮดของการเรียกใช้ฟังก์ชัน แต่ไม่เคยเสียสละความสามารถในการอ่านสำหรับประสิทธิภาพเว้นแต่คุณจะพบปัญหาคอขวดที่คุณต้องแก้ไข และวัดทุกครั้งเนื่องจากการใช้งานที่ชาญฉลาดบางอย่างสามารถปรับให้เหมาะสมและอินไลน์การเรียกใช้ฟังก์ชันบางอย่างในบางสถานการณ์
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
อย่างไรก็ตามโดยทั่วไปฉันยอมรับว่าหากคุณไม่มีตัวแปรมากกว่าสามตัวเวอร์ชันดั้งเดิมจะสามารถอ่านได้มากขึ้น
[x for x in range(pow(2,30)) if x != ((x * 2)/ pow(2,1))]
(a+b-c)*(a+c-b)*(b+c-a) == 0
หากผลรวมของสองเทอมใด ๆ เท่ากับเทอมที่สามดังนั้นหนึ่งในปัจจัยจะเป็นศูนย์ทำให้ผลิตภัณฑ์ทั้งหมดเป็นศูนย์
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
เพียงแค่:
a == b + c or abs(a) == abs(b - c)
โปรดทราบว่าสิ่งนี้จะไม่ทำงานหากตัวแปรไม่ได้ลงนาม
จากมุมมองของการเพิ่มประสิทธิภาพโค้ด (อย่างน้อยบนแพลตฟอร์ม x86) นี่น่าจะเป็นทางออกที่มีประสิทธิภาพที่สุด
คอมไพเลอร์ที่ทันสมัยจะ inline ทั้งเอบีเอส () ฟังก์ชั่นการโทรและการทดสอบสัญญาณหลีกเลี่ยงและสาขาเงื่อนไขที่ตามมาโดยใช้ลำดับฉลาดของ CDQ, แฮคเกอร์และคำแนะนำ รหัสระดับสูงด้านบนจะแสดงด้วยคำสั่ง ALU ที่มีความหน่วงแฝงต่ำและให้ปริมาณงานสูงเท่านั้นและเพียงสองเงื่อนไขเท่านั้น
fabs()
สามารถใช้สำหรับfloat
ประเภท;)
โซลูชันของ 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
เมื่อเขียนโค้ดที่คนอื่นจะต้องดูหรือฉันจะต้องดูอีกนานในภายหลังเมื่อฉันลืมสิ่งที่ฉันคิดเมื่อฉันเขียนมันสั้นหรือฉลาดเกินไปที่จะทำอันตรายมากกว่าดี รหัสควรอ่านได้ รวบรัดเป็นสิ่งที่ดี แต่ไม่ย่อท้อที่โปรแกรมเมอร์รายต่อไปไม่สามารถเข้าใจได้
คำขอมีขนาดกะทัดรัดมากขึ้นหรือ 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))))
g()
คุณต้องกำหนดเพื่อให้ทำงานได้ จากทั้งหมดนั้นฉันจะบอกว่ามันใหญ่กว่ามาก
ฉันต้องการนำเสนอสิ่งที่ฉันเห็นว่าเป็นคำตอบที่ไพเราะที่สุด:
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 เป็นหนึ่งในแนวคิดที่ยอดเยี่ยม - ลองทำสิ่งเหล่านี้ให้มากขึ้น!
ในฐานะที่เป็นนิสัยเก่าแก่ของการเขียนโปรแกรมของฉันฉันคิดว่าการวางนิพจน์ที่ซับซ้อนทางด้านขวาในประโยคสามารถทำให้อ่านง่ายขึ้นเช่นนี้
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))
ด้วยวิธีทั่วไป
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"
ฉันหลีกเลี่ยงการแบ่งแม้ว่ามันจะช่วยให้ใช้เพื่อหลีกเลี่ยงการคูณสองเพื่อหลีกเลี่ยงข้อผิดพลาดปัดเศษ อย่างไรก็ตามตรวจสอบโอเวอร์โฟลว์
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