@wwii Mereka tidak eksklusif satu sama lain. Lihat a = 0, b = 0, c = 0;)
Honza Brabec
1
Apa kata @phresnel. Alih-alih mencoba untuk "menyederhanakan" ekspresi, gabungkan dalam fungsi dengan nama deskriptif.
Cephalopod
Jawaban:
206
Jika kita melihat Zen of Python, tekankan milik saya:
The Zen of Python, oleh Tim Peters
Cantik itu lebih baik dari pada jelek.
Eksplisit lebih baik daripada implisit. Sederhana lebih baik daripada kompleks.
Kompleks lebih baik daripada rumit.
Datar lebih baik dari pada bersarang.
Sparse lebih baik dari pada padat. Keterbacaan itu penting.
Kasus khusus tidak cukup istimewa untuk melanggar aturan.
Meskipun kepraktisan mengalahkan kemurnian.
Kesalahan tidak boleh lewat diam-diam.
Kecuali dibungkam secara eksplisit.
Dalam menghadapi ambiguitas, tolak godaan untuk menebak. Seharusnya ada satu - dan sebaiknya hanya satu --cara yang jelas untuk melakukannya.
Meskipun cara itu mungkin tidak terlihat pada awalnya kecuali Anda orang Belanda.
Sekarang lebih baik daripada tidak sama sekali.
Meskipun tidak pernah lebih baik daritepat sekarang. Jika implementasinya sulit dijelaskan, itu ide yang buruk. Jika penerapannya mudah dijelaskan, mungkin itu ide yang bagus.
Namespaces adalah salah satu ide bagus - mari kita lakukan lebih banyak lagi!
Solusi paling Pythonic adalah yang paling jelas, paling sederhana, dan paling mudah dijelaskan:
a + b == c or a + c == b or b + c == a
Bahkan lebih baik lagi, Anda bahkan tidak perlu tahu Python untuk memahami kode ini! Semudah itu . Ini, tanpa syarat, adalah solusi terbaik. Yang lainnya adalah masturbasi intelektual.
Selain itu, ini kemungkinan merupakan solusi dengan kinerja terbaik juga, karena ini adalah satu-satunya dari semua proposal yang mengalami korsleting. Jika a + b == chanya dilakukan satu penjumlahan dan perbandingan.
Lebih baik lagi, masukkan beberapa tanda kurung untuk memperjelas maksudnya.
Bryan Oakley
3
Maksudnya sudah sangat jelas tanpa tanda kurung. Tanda kurung akan membuat lebih sulit untuk dibaca - mengapa penulis menggunakan tanda kurung padahal sebelumnya sudah mencakup ini?
Miles Rout
1
Satu catatan lain tentang mencoba menjadi terlalu pintar: Anda mungkin memperkenalkan bug yang tidak terduga dengan kondisi yang hilang yang tidak Anda pertimbangkan. Dengan kata lain, Anda mungkin mengira solusi ringkas baru Anda setara, tetapi tidak di semua kasus. Kecuali jika ada alasan kuat untuk membuat kode sebaliknya (kinerja, batasan memori, dan sebagainya), kejelasan adalah raja.
Rob Craig
Itu tergantung untuk apa rumus itu. Lihatlah 'Eksplisit lebih baik daripada implisit', mungkin pendekatan 'menyortir dulu' lebih jelas mengungkapkan apa yang dilakukan program, atau salah satu dari yang lain. Saya tidak berpikir kita bisa menilai dari pertanyaan itu.
Satu-satunya masalah dengan ini adalah efek sampingnya. Jika b atau c adalah ekspresi yang lebih kompleks, ekspresi tersebut akan dijalankan beberapa kali.
Siapapun yang membaca kode ini mungkin akan mengutuk Anda karena "pintar".
Karoly Horvath
5
@SilvioMayolo Hal yang sama berlaku untuk aslinya
Izkata
1
@AlexVarga, "Maksud saya adalah saya benar-benar menjawab pertanyaannya". Anda melakukannya; itu menggunakan karakter 30% lebih sedikit (memberi spasi antar operator). Saya tidak mencoba mengatakan jawaban Anda salah, hanya mengomentari betapa idiomatisnya (pythonic) itu. Jawaban bagus.
Paul Draper
54
Python memiliki anyfungsi yang mengerjakan orsemua elemen urutan. Di sini saya telah mengubah pernyataan Anda menjadi tupel 3 elemen.
any((a + b == c, a + c == b, b + c == a))
Perhatikan bahwa itu oradalah korsleting, jadi jika menghitung kondisi individu mahal, mungkin lebih baik menyimpan konstruksi asli Anda.
@ TigerhawkT3 Namun tidak dalam kasus ini; tiga ekspresi akan dievaluasi sebelum tupel ada, dan tupel akan ada anybahkan sebelum dijalankan.
aduk
13
Ah, begitu. Saya kira itu hanya ketika ada generator atau iterator malas serupa di sana.
TigerhawkT3
4
anydan all"memperpendek" proses memeriksa iterable yang diberikan; tetapi jika iterable itu adalah urutan dan bukan generator, maka iterable telah dievaluasi sepenuhnya sebelum pemanggilan fungsi terjadi .
Karl Knechtel
Ini memiliki keuntungan karena mudah untuk membagi menjadi beberapa baris (membuat indentasi ganda pada argumen any, membuat indentasi tunggal ):pada ifpernyataan), yang membantu banyak untuk keterbacaan saat matematika terlibat
Izkata
40
Jika Anda tahu Anda hanya berurusan dengan bilangan positif, ini akan berhasil, dan cukup bersih:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
Seperti yang saya katakan, ini hanya berfungsi untuk bilangan positif; tetapi jika Anda tahu mereka akan menjadi positif, ini adalah IMO solusi yang sangat mudah dibaca, bahkan secara langsung dalam kode sebagai lawan dalam suatu fungsi.
Anda dapat melakukan ini, yang mungkin melakukan sedikit penghitungan berulang; tetapi Anda tidak menetapkan kinerja sebagai sasaran Anda:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
Atau tanpa permutations()dan kemungkinan perhitungan berulang:
if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
do_stuff()
Saya mungkin akan menempatkan ini, atau solusi lain, ke dalam suatu fungsi. Kemudian Anda dapat memanggil fungsi dalam kode Anda dengan rapi.
Secara pribadi, kecuali saya membutuhkan lebih banyak fleksibilitas dari kode, saya hanya akan menggunakan metode pertama dalam pertanyaan Anda. Sederhana dan efisien. Saya mungkin masih memasukkannya ke dalam fungsi:
deftwo_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()
Itu cukup Pythonic, dan itu sangat mungkin cara paling efisien untuk melakukannya (fungsi tambahan memanggil samping); meskipun Anda tidak perlu terlalu khawatir tentang kinerja, kecuali itu benar-benar menyebabkan masalah.
terutama jika kita dapat mengasumsikan a, b, c semuanya non-negatif.
cphlewis
Saya menemukan frasa "tidak selalu berhasil" agak membingungkan. Solusi pertama hanya berfungsi jika Anda tahu pasti bahwa bilangan Anda bukan negatif. Misalnya dengan (a, b, c) = (-3, -2, -1) Anda memiliki a + b! = C tetapi b + c = a. Kasus serupa dengan (-1, 1, 2) dan (-2, -1, 1).
nomor pengguna
@usernumber, Anda tahu, saya perhatikan itu sebelumnya; tidak yakin mengapa saya tidak memperbaikinya.
Cyphase
Solusi teratas Anda tidak berfungsi untuk input kelas besar, sedangkan saran OP berfungsi untuk semua input. Bagaimana "tidak bekerja" lebih Pythonic daripada "bekerja"?
Barry
3
Ooh, jepret. " Jika Anda tahu Anda hanya berurusan dengan angka positif , ini akan berhasil, dan cukup bersih". Semua yang lain berfungsi untuk bilangan apa pun, tetapi jika Anda tahu bahwa Anda hanya berurusan dengan bilangan positif , yang teratas sangat mudah dibaca / IMO Pythonic.
Cyphase
17
Jika Anda hanya akan menggunakan tiga variabel maka metode awal Anda:
a + b == c or a + c == b or b + c == a
Apakah sudah sangat pythonic.
Jika Anda berencana menggunakan lebih banyak variabel maka metode penalaran Anda dengan:
a + b + c in (2*a, 2*b, 2*c)
Sangat pintar tetapi mari kita pikirkan mengapa. Mengapa ini berhasil?
Melalui beberapa aritmatika sederhana kita melihat bahwa:
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
Dan ini harus berlaku baik untuk a, b, atau c, yang berarti bahwa ya itu akan sama 2*a, 2*batau 2*c. Ini akan benar untuk sejumlah variabel.
Jadi cara yang baik untuk menulis ini dengan cepat adalah dengan membuat daftar variabel Anda dan memeriksa jumlahnya dengan daftar nilai yang digandakan.
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
Dengan cara ini, untuk menambahkan lebih banyak variabel ke dalam persamaan yang harus Anda lakukan adalah mengedit daftar nilai Anda dengan variabel baru 'n', bukan menulis persamaan 'n'
Bagaimana a=-1, b=-1, c=-2, kemudian a+b=c, namun a+b+c = -4, dan 2*max(a,b,c)adalah-2
Eric Renouf
Terima kasih itu benar, saya perlu menggunakan abs. Melakukan penyesuaian itu sekarang.
ThatGuyRussell
2
Setelah membumbui dengan setengah lusin abs()panggilan, itu Pythonic daripada cuplikan OP (saya sebenarnya akan menyebutnya kurang dapat dibaca secara signifikan).
TigerhawkT3
Itu sangat benar, saya akan menyesuaikannya sekarang
ThatGuyRussell
1
@ThatGuyRussell Untuk hubungan singkat, Anda ingin menggunakan generator ... sesuatu seperti any(sum(values) == 2*x for x in values), dengan cara itu Anda tidak perlu melakukan semua penggandaan di depan, seperti yang diperlukan.
Barry
12
Kode berikut dapat digunakan untuk membandingkan setiap elemen secara berulang dengan jumlah lainnya, yang dihitung dari jumlah seluruh daftar, tidak termasuk elemen itu.
Bagus :) Saya pikir jika Anda menghapus []tanda kurung dari baris kedua, ini bahkan akan korsleting seperti aslinya dengan or...
psmears
1
yang pada dasarnya any(a + b + c == 2*x for x in [a, b, c]), cukup dekat dengan saran OP
njzk2
Itu serupa, namun metode ini meluas ke sejumlah variabel. Saya memasukkan saran dari @psmears tentang hubungan arus pendek.
Arcanum
10
Jangan mencoba dan menyederhanakannya. Sebagai gantinya, sebutkan apa yang Anda lakukan dengan suatu fungsi:
defany_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):
...
Mengganti ketentuan dengan sesuatu yang "pintar" mungkin membuatnya lebih pendek, tetapi tidak akan membuatnya lebih mudah dibaca. Membiarkannya seperti itu juga tidak terlalu mudah dibaca, karena sulit untuk mengetahui mengapa Anda memeriksa ketiga kondisi tersebut secara sekilas. Ini membuatnya sangat jelas tentang apa yang Anda periksa.
Terkait performa, pendekatan ini memang menambahkan overhead panggilan fungsi, tetapi tidak pernah mengorbankan keterbacaan untuk performa kecuali Anda telah menemukan hambatan yang benar-benar harus Anda perbaiki. Dan selalu ukur, karena beberapa implementasi pintar mampu mengoptimalkan dan menyebariskan beberapa pemanggilan fungsi dalam beberapa keadaan.
Fungsi harus ditulis hanya jika Anda ingin menggunakan kode yang sama di lebih dari satu tempat atau jika kodenya rumit. Tidak ada penyebutan penggunaan kembali kode dalam pertanyaan awal, dan menulis fungsi untuk satu baris kode tidak hanya berlebihan tetapi sebenarnya merusak keterbacaan.
Igor Levicki
5
Berasal dari sekolah FP, saya cukup banyak harus tidak setuju sepenuhnya dan menyatakan bahwa fungsi satu baris yang dinamai dengan baik adalah beberapa alat terbaik untuk meningkatkan keterbacaan yang pernah Anda temukan. Jadikan fungsi setiap kali langkah yang Anda lakukan untuk melakukan sesuatu tidak langsung memberikan kejelasan pada apa yang Anda lakukan, karena nama fungsi memungkinkan Anda menentukan apa yang lebih baik daripada komentar mana pun.
Jack
Sekolah apa pun yang Anda ajak, adalah buruk untuk secara membabi buta mematuhi seperangkat aturan. Harus melompat ke bagian lain dari sumber untuk membaca bahwa satu baris kode yang disembunyikan di dalam suatu fungsi hanya untuk dapat memverifikasi bahwa itu benar-benar melakukan apa yang dikatakan dalam nama, dan kemudian harus beralih kembali ke tempat panggilan ke pastikan Anda mengirimkan parameter yang benar adalah pengalihan konteks yang sama sekali tidak perlu. Menurut pendapat saya, melakukan hal itu merusak keterbacaan dan alur kerja. Terakhir, baik nama fungsi maupun komentar kode merupakan pengganti yang tepat untuk dokumentasi kode.
Igor Levicki
9
Python 3:
(a+b+c)/2in (a,b,c)
(a+b+c+d)/2in (a,b,c,d)
...
Ini menskalakan ke sejumlah variabel:
arr = [a,b,c,d,...]
sum(arr)/2in arr
Namun, secara umum saya setuju bahwa kecuali Anda memiliki lebih dari tiga variabel, versi aslinya lebih mudah dibaca.
Ini mengembalikan hasil yang salah untuk beberapa input karena kesalahan pembulatan floating point.
poin
Divisi harus dihindari karena alasan kinerja dan akurasi.
Igor Levicki
1
@pts Apakah tidak ada implementasi yang mengembalikan hasil yang salah karena pembulatan floating point? Bahkan a + b == c
osundblad
@osundblad: Jika a, b dan c adalah ints, maka (a + b + c) / 2 melakukan pembulatan (dan mungkin mengembalikan hasil yang salah), tetapi a + b == c akurat.
poin
3
pembagian dengan 2 hanya mengurangi eksponen satu, sehingga akan akurat untuk bilangan bulat apa pun yang kurang dari 2 ^ 53 (bagian pecahan dari float di python), dan untuk bilangan bulat yang lebih besar Anda dapat menggunakan desimal . Misalnya, untuk memeriksa bilangan bulat yang kurang dari 2 ^ 30 jalankan[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
Jika hasil penjumlahan dua suku apa pun sama dengan suku ketiga, salah satu faktornya adalah nol, sehingga seluruh hasil kali menjadi nol.
Saya memikirkan hal yang persis sama tetapi saya tidak dapat menyangkal bahwa proposal aslinya jauh lebih bersih ...
pengguna541686
@Mehrdad - Pasti. Ini benar-benar tidak berbeda dengan(a+b<>c) && (a+c<>b) && (b+c<>a) == false
mbeckish
Hanya saja perkalian lebih mahal daripada ekspresi logika dan aritmatika dasar.
Igor Levicki
@IgorLevicki - Ya, meskipun itu adalah masalah pengoptimalan yang SANGAT prematur. Apakah ini akan dilakukan puluhan ribu kali per detik? Jika ya, Anda mungkin ingin melihat sesuatu yang lain.
mbeckish
@mbeckish - Mengapa menurut Anda ini terlalu dini? Kode harus ditulis dengan mempertimbangkan pengoptimalan, tidak dioptimalkan sebagai pemikiran setelahnya. Suatu hari nanti beberapa pekerja magang akan menyalin potongan kode ini dan menempelkannya ke dalam beberapa loop kritis kinerja pada platform tertanam yang kemudian akan berjalan di jutaan perangkat yang tidak selalu lambat untuk apa yang dilakukannya, tetapi mungkin menghabiskan lebih banyak daya baterai. Menulis kode seperti itu hanya mendorong praktik pengkodean yang buruk. Menurut saya, yang seharusnya ditanyakan OP adalah apakah ada cara untuk mengoptimalkan ekspresi logika itu.
Igor Levicki
6
Bagaimana dengan:
a == b + c or abs(a) == abs(b - c)
Perhatikan bahwa ini tidak akan berfungsi jika variabel tidak ditandatangani.
Dari sudut pandang pengoptimalan kode (setidaknya pada platform x86) ini tampaknya menjadi solusi yang paling efisien.
Kompiler modern akan menyebariskan kedua pemanggilan fungsi abs () dan menghindari pengujian tanda dan cabang bersyarat berikutnya dengan menggunakan urutan instruksi CDQ, XOR, dan SUB yang cerdas . Kode tingkat tinggi di atas dengan demikian akan diwakili dengan hanya latensi rendah, instruksi ALU throughput tinggi dan hanya dua kondisional.
Dan saya pikir fabs()bisa digunakan untuk floattipe;).
shA.t
4
Solusi yang diberikan oleh Alex Varga "a in (b + c, bc, cb)" kompak dan indah secara matematis, tetapi saya tidak akan benar-benar menulis kode seperti itu karena pengembang berikutnya yang datang tidak akan segera memahami tujuan kode tersebut .
Solusi Mark Ransom dari
any((a + b == c, a + c == b, b + c == a))
lebih jelas tetapi tidak lebih ringkas dari
a + b == c or a + c == b or b + c == a
Saat menulis kode yang harus dilihat oleh orang lain, atau yang akan saya lihat nanti ketika saya lupa apa yang saya pikirkan ketika saya menulisnya, terlalu pendek atau pintar cenderung lebih merugikan daripada menguntungkan. Kode harus dapat dibaca. Singkat itu bagus, tetapi tidak terlalu ringkas sehingga programmer berikutnya tidak dapat memahaminya.
Pertanyaan yang jujur: mengapa orang selalu berasumsi bahwa programmer berikutnya akan menjadi orang idiot yang tidak mampu membaca kode? Saya pribadi menganggap ide itu menghina. Jika kode harus ditulis agar jelas terlihat oleh setiap programmer, maka itu menyiratkan bahwa kita sebagai profesi melayani penyebut umum terendah, yang paling tidak terampil di antara kita. Jika kita terus melakukan itu, bagaimana mereka bisa meningkatkan keterampilan pribadinya? Saya tidak melihat ini di profesi lain. Kapan terakhir kali Anda melihat seorang komposer menulis musik sederhana agar setiap musisi dapat memainkannya terlepas dari tingkat keahliannya?
Igor Levicki
6
Masalahnya adalah bahwa pemrogram pun memiliki energi mental yang terbatas, jadi apakah Anda ingin menghabiskan energi mental Anda yang terbatas pada algoritme dan aspek program yang lebih tinggi, atau untuk mencari tahu arti beberapa baris kode yang rumit ketika dapat diekspresikan dengan lebih sederhana ? Pemrograman itu sulit, jadi jangan mempersulit diri Anda secara tidak perlu, sama seperti pelari Olimpiade tidak akan mengikuti perlombaan dengan membawa tas punggung yang berat hanya karena mereka bisa. Seperti yang dikatakan Steve McConell dalam Code Complete 2, keterbacaan adalah salah satu aspek terpenting dari kode.
Paul J Abernathy
2
Permintaan untuk lebih kompak ATAU lebih pythonic - Saya mencoba tangan saya lebih kompak.
diberikan
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
defg(x,y,z):return x + y == z
Ini adalah 2 karakter kurang dari aslinya
any(g(*args) for args in f((a,b,c)))
uji dengan:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
Yah, itu dua karakter lebih pendek dari aslinya, tapi bukan yang diberikan OP setelahnya, yang dia katakan sedang dia gunakan. Dokumen asli juga menyertakan banyak spasi, yang akan dihilangkan jika memungkinkan. Ada juga masalah kecil dari fungsi g()yang harus Anda tentukan agar ini berfungsi. Mengingat semua itu, menurut saya itu jauh lebih besar.
TigerhawkT3
@ TigerhawkT3, saya menafsirkannya sebagai permintaan untuk ekspresi / baris yang lebih pendek. lihat edit untuk perbaikan lebih lanjut .
Perang Dunia II
4
Nama fungsi yang sangat buruk, hanya cocok untuk kode golf.
0xc0de
@ 0xc0de - maaf saya tidak bermain. Cocok bisa sangat subjektif dan tergantung pada keadaan - tetapi saya akan tunduk pada komunitas.
Perang Dunia II
Saya tidak melihat bagaimana ini lebih kompak ketika memiliki lebih banyak karakter daripada kode aslinya.
Igor Levicki
1
Saya ingin menyajikan apa yang saya lihat sebagai jawaban paling pythonic :
defone_number_is_the_sum_of_the_others(a, b, c):return any((a == b + c, b == a + c, c == a + b))
Kasus umum, tidak dioptimalkan:
defone_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):
returnTruereturnFalse
Dalam hal Zen of Python, saya pikir pernyataan yang ditekankan lebih banyak diikuti daripada dari jawaban lain:
The Zen of Python, oleh Tim Peters
Cantik itu lebih baik dari pada jelek. Eksplisit lebih baik daripada implisit. Sederhana lebih baik daripada kompleks.
Kompleks lebih baik daripada rumit.
Datar lebih baik dari pada bersarang.
Sparse lebih baik dari pada padat. Keterbacaan itu penting.
Kasus khusus tidak cukup istimewa untuk melanggar aturan.
Meskipun kepraktisan mengalahkan kemurnian.
Kesalahan tidak boleh lewat diam-diam.
Kecuali dibungkam secara eksplisit.
Dalam menghadapi ambiguitas, tolak godaan untuk menebak.
Seharusnya ada satu - dan sebaiknya hanya satu --cara yang jelas untuk melakukannya.
Meskipun cara itu mungkin tidak terlihat pada awalnya kecuali Anda orang Belanda.
Sekarang lebih baik daripada tidak sama sekali.
Meskipun tidak pernah lebih baik daritepat sekarang.
Jika implementasinya sulit dijelaskan, itu ide yang buruk.
Jika penerapannya mudah dijelaskan, mungkin itu ide yang bagus.
Namespaces adalah salah satu ide bagus - mari kita lakukan lebih banyak lagi!
Sebagai kebiasaan lama pemrograman saya, saya pikir menempatkan ekspresi kompleks di kanan dalam klausa dapat membuatnya lebih mudah dibaca seperti ini:
a == b+c or b == a+c or c == a+b
Plus ():
((a == b+c) or (b == a+c) or (c == a+b))
Dan juga saya pikir menggunakan multi-garis juga bisa membuat lebih banyak indra seperti ini:
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
jika, memanipulasi variabel input tidak masalah untuk Anda,
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
jika Anda ingin mengeksploitasi menggunakan bit hacks, Anda dapat menggunakan "!", ">> 1" dan "<< 1"
Saya menghindari pembagian meskipun itu memungkinkan penggunaan untuk menghindari dua perkalian untuk menghindari kesalahan pembulatan. Namun, periksa overflow
Fungsi harus ditulis hanya jika Anda ingin menggunakan kode yang sama di lebih dari satu tempat atau jika kodenya rumit. Tidak ada penyebutan penggunaan kembali kode dalam pertanyaan awal, dan menulis fungsi untuk satu baris kode tidak hanya berlebihan tetapi sebenarnya merusak keterbacaan.
Igor Levicki
Saya tidak setuju bahwa itu merusak keterbacaan; jika Anda memilih nama yang sesuai, itu dapat meningkatkan keterbacaan (tetapi saya tidak membuat representasi tentang kualitas nama yang saya pilih dalam jawaban ini). Selain itu, memberi nama pada sebuah konsep dapat membantu, yang harus Anda lakukan selama Anda memaksakan diri untuk memberi nama yang baik pada fungsi Anda. Fungsinya bagus. Mengenai apakah fungsionalitasnya cukup kompleks untuk mendapatkan manfaat dari dikemas dalam suatu fungsi, itu adalah penilaian subjektif.
Jawaban:
Jika kita melihat Zen of Python, tekankan milik saya:
Solusi paling Pythonic adalah yang paling jelas, paling sederhana, dan paling mudah dijelaskan:
a + b == c or a + c == b or b + c == a
Bahkan lebih baik lagi, Anda bahkan tidak perlu tahu Python untuk memahami kode ini! Semudah itu . Ini, tanpa syarat, adalah solusi terbaik. Yang lainnya adalah masturbasi intelektual.
Selain itu, ini kemungkinan merupakan solusi dengan kinerja terbaik juga, karena ini adalah satu-satunya dari semua proposal yang mengalami korsleting. Jika
a + b == c
hanya dilakukan satu penjumlahan dan perbandingan.sumber
Memecahkan tiga persamaan untuk:
a in (b+c, b-c, c-b)
sumber
Python memiliki
any
fungsi yang mengerjakanor
semua elemen urutan. Di sini saya telah mengubah pernyataan Anda menjadi tupel 3 elemen.Perhatikan bahwa itu
or
adalah korsleting, jadi jika menghitung kondisi individu mahal, mungkin lebih baik menyimpan konstruksi asli Anda.sumber
any()
danall()
korsleting juga.any
bahkan sebelum dijalankan.any
danall
"memperpendek" proses memeriksa iterable yang diberikan; tetapi jika iterable itu adalah urutan dan bukan generator, maka iterable telah dievaluasi sepenuhnya sebelum pemanggilan fungsi terjadi .any
, membuat indentasi tunggal):
padaif
pernyataan), yang membantu banyak untuk keterbacaan saat matematika terlibatJika Anda tahu Anda hanya berurusan dengan bilangan positif, ini akan berhasil, dan cukup bersih:
a, b, c = sorted((a, b, c)) if a + b == c: do_stuff()
Seperti yang saya katakan, ini hanya berfungsi untuk bilangan positif; tetapi jika Anda tahu mereka akan menjadi positif, ini adalah IMO solusi yang sangat mudah dibaca, bahkan secara langsung dalam kode sebagai lawan dalam suatu fungsi.
Anda dapat melakukan ini, yang mungkin melakukan sedikit penghitungan berulang; tetapi Anda tidak menetapkan kinerja sebagai sasaran Anda:
from itertools import permutations if any(x + y == z for x, y, z in permutations((a, b, c), 3)): do_stuff()
Atau tanpa
permutations()
dan kemungkinan perhitungan berulang:if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]: do_stuff()
Saya mungkin akan menempatkan ini, atau solusi lain, ke dalam suatu fungsi. Kemudian Anda dapat memanggil fungsi dalam kode Anda dengan rapi.
Secara pribadi, kecuali saya membutuhkan lebih banyak fleksibilitas dari kode, saya hanya akan menggunakan metode pertama dalam pertanyaan Anda. Sederhana dan efisien. Saya mungkin masih memasukkannya ke dalam fungsi:
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()
Itu cukup Pythonic, dan itu sangat mungkin cara paling efisien untuk melakukannya (fungsi tambahan memanggil samping); meskipun Anda tidak perlu terlalu khawatir tentang kinerja, kecuali itu benar-benar menyebabkan masalah.
sumber
Jika Anda hanya akan menggunakan tiga variabel maka metode awal Anda:
a + b == c or a + c == b or b + c == a
Apakah sudah sangat pythonic.
Jika Anda berencana menggunakan lebih banyak variabel maka metode penalaran Anda dengan:
a + b + c in (2*a, 2*b, 2*c)
Sangat pintar tetapi mari kita pikirkan mengapa. Mengapa ini berhasil?
Melalui beberapa aritmatika sederhana kita melihat bahwa:
a + b = c c = c a + b + c == c + c == 2*c a + b + c == 2*c
Dan ini harus berlaku baik untuk a, b, atau c, yang berarti bahwa ya itu akan sama
2*a
,2*b
atau2*c
. Ini akan benar untuk sejumlah variabel.Jadi cara yang baik untuk menulis ini dengan cepat adalah dengan membuat daftar variabel Anda dan memeriksa jumlahnya dengan daftar nilai yang digandakan.
values = [a,b,c,d,e,...] any(sum(values) in [2*x for x in values])
Dengan cara ini, untuk menambahkan lebih banyak variabel ke dalam persamaan yang harus Anda lakukan adalah mengedit daftar nilai Anda dengan variabel baru 'n', bukan menulis persamaan 'n'
sumber
a=-1
,b=-1
,c=-2
, kemudiana+b=c
, namuna+b+c = -4
, dan2*max(a,b,c)
adalah-2
abs()
panggilan, itu Pythonic daripada cuplikan OP (saya sebenarnya akan menyebutnya kurang dapat dibaca secara signifikan).any(sum(values) == 2*x for x in values)
, dengan cara itu Anda tidak perlu melakukan semua penggandaan di depan, seperti yang diperlukan.Kode berikut dapat digunakan untuk membandingkan setiap elemen secara berulang dengan jumlah lainnya, yang dihitung dari jumlah seluruh daftar, tidak termasuk elemen itu.
l = [a,b,c] any(sum(l)-e == e for e in l)
sumber
[]
tanda kurung dari baris kedua, ini bahkan akan korsleting seperti aslinya denganor
...any(a + b + c == 2*x for x in [a, b, c])
, cukup dekat dengan saran OPJangan mencoba dan menyederhanakannya. Sebagai gantinya, sebutkan apa yang Anda lakukan dengan suatu fungsi:
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): ...
Mengganti ketentuan dengan sesuatu yang "pintar" mungkin membuatnya lebih pendek, tetapi tidak akan membuatnya lebih mudah dibaca. Membiarkannya seperti itu juga tidak terlalu mudah dibaca, karena sulit untuk mengetahui mengapa Anda memeriksa ketiga kondisi tersebut secara sekilas. Ini membuatnya sangat jelas tentang apa yang Anda periksa.
Terkait performa, pendekatan ini memang menambahkan overhead panggilan fungsi, tetapi tidak pernah mengorbankan keterbacaan untuk performa kecuali Anda telah menemukan hambatan yang benar-benar harus Anda perbaiki. Dan selalu ukur, karena beberapa implementasi pintar mampu mengoptimalkan dan menyebariskan beberapa pemanggilan fungsi dalam beberapa keadaan.
sumber
Python 3:
(a+b+c)/2 in (a,b,c) (a+b+c+d)/2 in (a,b,c,d) ...
Ini menskalakan ke sejumlah variabel:
arr = [a,b,c,d,...] sum(arr)/2 in arr
Namun, secara umum saya setuju bahwa kecuali Anda memiliki lebih dari tiga variabel, versi aslinya lebih mudah dibaca.
sumber
[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
Jika hasil penjumlahan dua suku apa pun sama dengan suku ketiga, salah satu faktornya adalah nol, sehingga seluruh hasil kali menjadi nol.
sumber
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
Bagaimana dengan:
a == b + c or abs(a) == abs(b - c)
Perhatikan bahwa ini tidak akan berfungsi jika variabel tidak ditandatangani.
Dari sudut pandang pengoptimalan kode (setidaknya pada platform x86) ini tampaknya menjadi solusi yang paling efisien.
Kompiler modern akan menyebariskan kedua pemanggilan fungsi abs () dan menghindari pengujian tanda dan cabang bersyarat berikutnya dengan menggunakan urutan instruksi CDQ, XOR, dan SUB yang cerdas . Kode tingkat tinggi di atas dengan demikian akan diwakili dengan hanya latensi rendah, instruksi ALU throughput tinggi dan hanya dua kondisional.
sumber
fabs()
bisa digunakan untukfloat
tipe;).Solusi yang diberikan oleh Alex Varga "a in (b + c, bc, cb)" kompak dan indah secara matematis, tetapi saya tidak akan benar-benar menulis kode seperti itu karena pengembang berikutnya yang datang tidak akan segera memahami tujuan kode tersebut .
Solusi Mark Ransom dari
lebih jelas tetapi tidak lebih ringkas dari
a + b == c or a + c == b or b + c == a
Saat menulis kode yang harus dilihat oleh orang lain, atau yang akan saya lihat nanti ketika saya lupa apa yang saya pikirkan ketika saya menulisnya, terlalu pendek atau pintar cenderung lebih merugikan daripada menguntungkan. Kode harus dapat dibaca. Singkat itu bagus, tetapi tidak terlalu ringkas sehingga programmer berikutnya tidak dapat memahaminya.
sumber
Permintaan untuk lebih kompak ATAU lebih pythonic - Saya mencoba tangan saya lebih kompak.
diberikan
import functools, itertools f = functools.partial(itertools.permutations, r = 3) def g(x,y,z): return x + y == z
Ini adalah 2 karakter kurang dari aslinya
any(g(*args) for args in f((a,b,c)))
uji dengan:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
Selain itu, diberikan:
Ini setara
sumber
g()
yang harus Anda tentukan agar ini berfungsi. Mengingat semua itu, menurut saya itu jauh lebih besar.Saya ingin menyajikan apa yang saya lihat sebagai jawaban paling pythonic :
def one_number_is_the_sum_of_the_others(a, b, c): return any((a == b + c, b == a + c, c == a + b))
Kasus umum, tidak dioptimalkan:
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
Dalam hal Zen of Python, saya pikir pernyataan yang ditekankan lebih banyak diikuti daripada dari jawaban lain:
sumber
Sebagai kebiasaan lama pemrograman saya, saya pikir menempatkan ekspresi kompleks di kanan dalam klausa dapat membuatnya lebih mudah dibaca seperti ini:
a == b+c or b == a+c or c == a+b
Plus
()
:((a == b+c) or (b == a+c) or (c == a+b))
Dan juga saya pikir menggunakan multi-garis juga bisa membuat lebih banyak indra seperti ini:
((a == b+c) or (b == a+c) or (c == a+b))
sumber
Secara umum,
m = a+b-c; if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
jika, memanipulasi variabel input tidak masalah untuk Anda,
c = a+b-c; if (c==0 || c == 2*a || c == 2*b) do_stuff ();
jika Anda ingin mengeksploitasi menggunakan bit hacks, Anda dapat menggunakan "!", ">> 1" dan "<< 1"
Saya menghindari pembagian meskipun itu memungkinkan penggunaan untuk menghindari dua perkalian untuk menghindari kesalahan pembulatan. Namun, periksa overflow
sumber
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
sumber