Bagaimana saya bisa melakukan ini secara elegan dengan C # dan .NET 3.5 / 4?
Misalnya, angka bisa antara 1 dan 100.
Saya tahu sederhana jika cukup; tetapi kata kunci untuk pertanyaan ini adalah keanggunan. Ini untuk proyek mainan saya bukan untuk produksi.
Pertanyaan ini bukan tentang kecepatan, tetapi tentang keindahan kode. Berhentilah berbicara tentang efisiensi dan semacamnya; ingat Anda sedang mengabar ke paduan suara.
if
bukan "barok" jangan memperbaikinya.Jawaban:
Ada banyak opsi:
Juga, lihat pos SO ini untuk opsi regex.
sumber
if
pernyataan. Ini tentu saja mencapai itu ...;)Maksudmu?
atau
sumber
Untuk menambah derau di sini, Anda dapat membuat metode ekstensi:
Yang akan membiarkan Anda melakukan sesuatu seperti ...
Yang sedang berkata, ini sepertinya hal yang konyol untuk dilakukan ketika cek itu sendiri hanya satu baris.
sumber
Seperti yang dikatakan orang lain, gunakan if sederhana.
Anda harus memikirkan pemesanan.
misalnya
lebih mudah dibaca daripada
sumber
1 <= x <= 100
.=
alih-alih==
. Ini tidak membantu operator relasional non-kesetaraan - tetapi mudah digunakan untuk menggunakannya secara konsisten.x
adalah pemanggilan fungsi yang kompleks atau ekspresi Linq yang menghabiskan waktu. Dalam hal ini Anda akan melakukan ini dua kali yang bukan hal yang baik. Tentu Anda harus menyimpan nilai ke dalam variabel lokal sementara tetapi ada beberapa kasus (misalnya di lain-jika-pernyataan) di mana Anda hanya ingin memanggil fungsi setelah yang lain jika atau jika-jika gagal. Dengan variabel sementara Anda harus tetap memanggilnya sebelumnya. Metode ekstensi (disebutkan dalam jawaban lain) adalah solusi imho terbaik dalam kasus tersebut.Dalam kode produksi saya hanya akan menulis
Ini mudah dimengerti dan sangat mudah dibaca.
Berikut ini adalah metode pintar yang mengurangi jumlah perbandingan dari dua menjadi satu dengan menggunakan beberapa matematika. Idenya adalah bahwa salah satu dari dua faktor menjadi negatif jika angka tersebut berada di luar rentang dan nol jika jumlahnya sama dengan salah satu batas:
Jika batasannya inklusif:
atau
Jika batasannya eksklusif:
atau
sumber
1 < x && x < 100
kode produktif yang sederhana . Lebih mudah dimengerti.1 < x & x < 100
(tidak ada && hubung singkat) menginstruksikan kompiler bahwa ia selalu dapat mengevaluasix < 100
terlepas dari hasil1 < x
. Anehnya (karena prediksi cabang) lebih cepat untuk selalu melakukan operasi sederhana ini daripada kadang-kadang melewatkannya.Saya mengusulkan ini:
Contoh:
dan tentu saja dengan variabel:
Mudah dibaca (dekat dengan bahasa manusia) dan berfungsi dengan jenis apa pun yang sebanding (bilangan bulat, ganda, jenis khusus ...).
Memiliki kode yang mudah dibaca adalah penting karena pengembang tidak akan menyia-nyiakan "siklus otak" untuk memahaminya. Dalam sesi pengkodean yang panjang, siklus otak yang terbuang membuat pengembang lelah lebih awal dan rentan terhadap bug.
sumber
IsInRange. I'm not that keen on Ben's inclusive boolean as that requires a few more brain cycles. It has the advantage that it can be used in any class that that implements IComparer. This is in my Extensions now along with
LiesWithin /LiesInside. Just can't decide which.
NotOutside akan berfungsi tetapi saya tidak suka kondisi negatifDengan sedikit penyalahgunaan metode ekstensi, kita bisa mendapatkan solusi "elegan" berikut:
sumber
enum Inclusive
dengan nilai-nilai:Lower
,Upper
,All
. Dan lulus untukIn
fungsi satu parameter tambahan jenisenum Inclusive
dengan nilai defaultInclusive.All
, memperbaruiTo
fungsi tubuh untuk menanganiAll
,Lower
,Upper
nilai-nilai :)Jika ini insidentil, sederhanalah
if
yang Anda butuhkan. Jika ini terjadi di banyak tempat, Anda mungkin ingin mempertimbangkan keduanya:Sesuatu seperti:
sumber
sumber
Menggunakan
&&
ekspresi untuk bergabung dengan dua perbandingan hanyalah cara paling elegan untuk melakukan ini. Jika Anda mencoba menggunakan metode ekstensi mewah dan semacamnya, Anda mengalami pertanyaan apakah akan menyertakan batas atas, batas bawah, atau keduanya. Setelah Anda mulai menambahkan variabel tambahan atau mengubah nama ekstensi untuk menunjukkan apa yang disertakan, kode Anda menjadi lebih lama dan lebih sulit dibaca (untuk sebagian besar programmer). Selain itu, alat seperti Resharper akan memperingatkan Anda jika perbandingan Anda tidak masuk akal (number > 100 && number < 1
), yang tidak akan mereka lakukan jika Anda menggunakan metode ('i.IsBetween (100, 1)').Satu-satunya komentar lain yang akan saya buat adalah bahwa jika Anda memeriksa input dengan maksud untuk melemparkan pengecualian, Anda harus mempertimbangkan untuk menggunakan kontrak kode:
Ini lebih elegan daripada
if(...) throw new Exception(...)
, dan Anda bahkan bisa mendapatkan peringatan waktu kompilasi jika seseorang mencoba memanggil metode Anda tanpa memastikan bahwa nomor tersebut berada dalam batas pertama.sumber
Jika Anda ingin menulis lebih banyak kode daripada kode sederhana, mungkin Anda dapat: Membuat Metode Ekstensi yang disebut IsBetween
...
Tambahan:perlu dicatat bahwa dalam praktiknya Anda sangat jarang "hanya memeriksa kesetaraan" (atau <,>) dalam basis kode. (Selain dari dalam situasi yang paling sepele.) Murni sebagai contoh, setiap programmer game akan menggunakan kategori seperti berikut ini di setiap proyek, sebagai masalah dasar. Perhatikan bahwa dalam contoh ini (kebetulan) menggunakan fungsi (Mathf. Mungkin) yang dibangun di lingkungan itu; dalam praktiknya Anda biasanya harus dengan hati-hati mengembangkan konsep Anda sendiri tentang apa artinya perbandingan untuk representasi komputer dari bilangan real, untuk jenis situasi yang Anda rekayasa. (Bahkan tidak menyebutkan bahwa jika Anda melakukan sesuatu seperti, mungkin pengontrol, pengontrol PID atau sejenisnya, seluruh masalah menjadi pusat dan sangat sulit, itu menjadi sifat proyek.
sumber
return (value >= Min && value <= Max);
Karena semua jawaban lain tidak ditemukan oleh saya, di sini hanya implementasi saya:
Anda kemudian dapat menggunakannya seperti ini:
sumber
EDIT: Jawaban Baru disediakan. Saya baru mulai menggunakan C # ketika saya menulis jawaban pertama untuk pertanyaan ini, dan di belakang saya sekarang menyadari bahwa "solusi" saya adalah naif dan tidak efisien.
Jawaban asli saya: Saya akan menggunakan versi yang lebih sederhana:
if(Enumerable.Range(1,100).Contains(intInQuestion)) { ...DoStuff; }
A Better Way
Karena saya belum melihat solusi lain yang lebih efisien (menurut tes saya setidaknya), saya akan mencobanya lagi.
Cara baru dan lebih baik yang juga berfungsi dengan rentang negatif :
Ini dapat digunakan dengan rentang positif dan negatif dan default ke kisaran
1..100 (inklusif) dan digunakan
x
sebagai nomor untuk memeriksa diikuti oleh rentang opsional yang ditentukan olehmin
danmax
.Menambahkan Contoh Untuk Ukuran Yang Baik
Contoh 1:
Pengembalian:
Contoh 2: Menggunakan daftar int acak antara 1 dan 150
Pengembalian:
Waktu Eksekusi: 0,016 detik
sumber
Sentuhan baru pada favorit lama:
sumber
Dalam C, jika efisiensi waktu sangat penting dan overflow bilangan bulat akan membungkus, orang bisa melakukannya
if ((unsigned)(value-min) <= (max-min)) ...
. Jika 'max' dan 'min' adalah variabel independen, pengurangan ekstra untuk (max-min) akan membuang waktu, tetapi jika ekspresi itu dapat dikomputasi pada waktu kompilasi, atau jika itu dapat dihitung sekali pada saat run-time untuk menguji banyak angka terhadap rentang yang sama, ekspresi di atas dapat dihitung secara efisien bahkan dalam kasus di mana nilai berada dalam kisaran (jika sebagian besar nilai akan berada di bawah rentang yang valid, mungkin lebih cepat digunakanif ((value >= min) && (value <= max)) ...
karena akan keluar lebih awal jika nilai kurang dari min).Namun, sebelum menggunakan implementasi seperti itu, patok mesin target seseorang. Pada beberapa prosesor, ekspresi dua bagian mungkin lebih cepat dalam semua kasus karena dua perbandingan dapat dilakukan secara independen sedangkan dalam metode kurangi dan bandingkan pengurangan harus diselesaikan sebelum perbandingan dapat dieksekusi.
sumber
Bagaimana dengan sesuatu yang seperti ini?
dengan metode ekstensi sebagai berikut (diuji):
sumber
Saya akan melakukan objek Range, sesuatu seperti ini:
Maka Anda menggunakannya dengan cara ini:
Dengan begitu Anda dapat menggunakannya kembali untuk jenis lain.
sumber
Range
Objek Anda perlu menggunakanCompareTo
metode untuk membandingkan item, bukan<
operator.IComparable
dan tidak membebani<
operator.Saat memeriksa apakah "Angka" dalam kisaran Anda harus jelas dalam apa yang Anda maksud, dan apa artinya dua angka sama? Secara umum Anda harus membungkus semua angka floating point dalam apa yang disebut 'bola epsilon' ini dilakukan dengan memilih beberapa nilai kecil dan mengatakan jika dua nilai sedekat ini mereka adalah hal yang sama.
Dengan dua pembantu ini di tempat dan dengan asumsi bahwa jika nomor apa pun dapat dilemparkan sebagai ganda tanpa akurasi yang diperlukan. Yang Anda butuhkan sekarang adalah enum dan metode lain
Metode lain berikut:
Sekarang ini mungkin jauh lebih dari apa yang Anda inginkan, tetapi itu membuat Anda tidak berurusan dengan pembulatan sepanjang waktu dan mencoba mengingat jika suatu nilai telah dibulatkan dan ke tempat apa. Jika perlu, Anda dapat dengan mudah memperpanjang ini untuk bekerja dengan epsilon apa pun dan untuk memungkinkan epsilon Anda berubah.
sumber
Pemakaian
double numberToBeChecked = 7;
var result = numberToBeChecked.IsBetween (100.122);
hasil var = 5.IsBetween (100.120);
var result = 8.0.IsBetween (1.2,9.6);
sumber
Jika Anda khawatir dengan komentar oleh @Daap pada jawaban yang diterima dan hanya dapat memberikan nilai satu kali, Anda dapat mencoba salah satu dari yang berikut ini
atau
sumber
Mengenai keanggunan, hal terdekat dengan notasi matematika ( a <= x <= b ) sedikit meningkatkan keterbacaan:
Untuk ilustrasi lebih lanjut:
sumber
Saya sedang mencari cara yang elegan untuk melakukannya di mana batas mungkin diaktifkan (mis. Tidak yakin urutan nilai-nilai yang ada di).
Ini hanya akan berfungsi pada versi C # yang lebih baru di mana?: Ada
Jelas Anda bisa mengubah tanda = di sana untuk tujuan Anda. Bisa juga menyukai tipe casting. Saya hanya perlu pengembalian mengambang dalam batas (atau sama dengan)
sumber
Elegan karena tidak mengharuskan Anda menentukan mana dari dua nilai batas yang lebih dulu. Ini juga tidak mengandung cabang.
sumber
Saya tidak tahu tetapi saya menggunakan metode ini:
Dan inilah cara saya dapat menggunakannya:
sumber
Ini adalah beberapa metode Ekstensi yang dapat membantu
sumber
Jika itu untuk memvalidasi parameter metode, tidak ada solusi yang membuang ArgumentOutOfRangeException dan memungkinkan konfigurasi yang mudah / tepat untuk nilai inklusif / eksklusif min / maks.
Gunakan seperti ini
Saya baru saja menulis fungsi-fungsi yang indah ini. Ini juga memiliki keuntungan karena tidak memiliki percabangan (jika tunggal) untuk nilai yang valid. Bagian tersulit adalah menyusun pesan pengecualian yang tepat.
sumber
Anda mencari
in [1..100]
? Itu hanya Pascal.sumber
when (number) { in 0..9 -> println("1 digit") in 10..99 -> println("2 digits") in 100..999 -> println("3 digits") }