Saya perlu bergerak mundur melalui array, jadi saya memiliki kode seperti ini:
for (int i = myArray.Length - 1; i >= 0; i--)
{
// Do something
myArray[i] = 42;
}
Apakah ada cara yang lebih baik untuk melakukan ini?
Pembaruan: Saya berharap mungkin C # memiliki beberapa mekanisme bawaan untuk ini seperti:
foreachbackwards (int i in myArray)
{
// so easy
}
Update 2: Ada yang cara yang lebih baik. Rune mengambil hadiah dengan:
for (int i = myArray.Length; i-- > 0; )
{
//do something
}
//or
for (int i = myArray.Length; i --> 0; )
{
// do something
}
yang terlihat lebih baik di C biasa (berkat Twotymz):
for (int i = lengthOfArray; i--; )
{
//do something
}
Jawaban:
Meskipun memang agak tidak jelas, saya akan mengatakan bahwa cara tipografi yang paling menyenangkan untuk melakukan ini adalah
sumber
Di C ++ pada dasarnya Anda memiliki pilihan antara iterasi menggunakan iterator, atau indeks. Bergantung pada apakah Anda memiliki array biasa, atau
std::vector
, Anda menggunakan teknik yang berbeda.Menggunakan std :: vector
Menggunakan iterator
C ++ memungkinkan Anda melakukan ini menggunakan
std::reverse_iterator:
Menggunakan indeks
Jenis integral unsigned dikembalikan oleh
std::vector<T>::size
yang tidak selalustd::size_t
. Bisa lebih besar atau lebih kecil. Ini penting agar loop berfungsi.Ini berfungsi, karena nilai tipe integral unsigned ditentukan dengan menggunakan modulo jumlah bitnya. Jadi, jika Anda menyetel
-N
, Anda berakhir di(2 ^ BIT_SIZE) -N
Menggunakan Array
Menggunakan iterator
Kami menggunakan
std::reverse_iterator
untuk melakukan iterasi.Menggunakan indeks
Kami dapat menggunakan dengan aman di
std::size_t
sini, sebagai lawan di atas, karenasizeof
selalu mengembalikanstd::size_t
menurut definisi.Menghindari jebakan dengan ukuran yang diterapkan pada pointer
Sebenarnya cara di atas untuk menentukan ukuran array menyebalkan. Jika a sebenarnya adalah sebuah pointer dan bukan sebuah array (yang sering terjadi, dan pemula akan bingung), itu akan gagal secara diam-diam. Cara yang lebih baik adalah dengan menggunakan yang berikut ini, yang akan gagal pada waktu kompilasi, jika diberi pointer:
Ia bekerja dengan mendapatkan ukuran dari larik yang diteruskan terlebih dahulu, lalu mendeklarasikan untuk mengembalikan referensi ke larik bertipe char dengan ukuran yang sama.
char
didefinisikan memilikisizeof
: 1. Jadi array yang dikembalikan akan memilikisizeof
: N * 1, yang kita cari, dengan hanya evaluasi waktu kompilasi dan overhead runtime nol.Daripada melakukan
Ubah kode Anda sehingga sekarang bisa
sumber
end
danbegin
dalam urutan terbalik?Di C # , menggunakan Visual Studio 2005 atau yang lebih baru, ketik 'forr' dan tekan [TAB] [TAB] . Ini akan meluas ke
for
loop yang mundur melalui koleksi.Sangat mudah untuk salah (setidaknya bagi saya), sehingga saya pikir memasukkan potongan ini adalah ide yang bagus.
Meskipun demikian, saya suka
Array.Reverse()
/Enumerable.Reverse()
dan kemudian mengulanginya ke depan dengan lebih baik - mereka menyatakan niat dengan lebih jelas.sumber
Saya selalu lebih suka kode yang jelas daripada kode yang 'secara tipografis menyenangkan '. Jadi, saya akan selalu menggunakan:
Anda dapat menganggapnya sebagai cara standar untuk memutar mundur.
Hanya dua sen saya ...
sumber
Di C # menggunakan Linq :
sumber
Itu pasti cara terbaik untuk larik apa pun yang panjangnya merupakan tipe integral bertanda. Untuk array yang panjangnya merupakan tipe integral unsigned (misalnya
std::vector
dalam C ++), maka Anda perlu sedikit mengubah kondisi akhir:Jika Anda baru saja mengatakan
i >= 0
, ini selalu benar untuk integer yang tidak bertanda tangan, jadi loop akan menjadi loop tanpa batas.sumber
Terlihat bagus untukku. Jika pengindeks tidak ditandatangani (uint dll), Anda mungkin harus mempertimbangkannya. Panggil saya malas, tetapi dalam kasus (unsigned) itu, saya mungkin hanya menggunakan variabel-counter:
(sebenarnya, bahkan di sini Anda harus berhati-hati terhadap kasus seperti arr.Length = uint.MaxValue ... mungkin a! = di suatu tempat ... tentu saja, itu kasus yang sangat tidak mungkin!)
sumber
Di CI suka melakukan ini:
Contoh C # ditambahkan oleh MusiGenesis:
sumber
Cara terbaik untuk melakukannya di C ++ mungkin dengan menggunakan adaptor iterator (atau lebih baik, range), yang dengan malas akan mengubah urutan saat sedang dilalui.
Pada dasarnya,
Menampilkan rentang "rentang" (di sini, kosong, tapi saya cukup yakin Anda dapat menambahkan elemen sendiri) dalam urutan terbalik. Tentu saja mengiterasi rentang tersebut tidak banyak gunanya, tetapi meneruskan rentang baru itu ke algoritme dan hal-hal lainnya cukup keren.
Mekanisme ini juga dapat digunakan untuk penggunaan yang jauh lebih kuat:
Akan dengan malas menghitung rentang "rentang", di mana fungsi "f" diterapkan ke semua elemen, elemen yang "p" tidak benar akan dihapus, dan akhirnya rentang yang dihasilkan dibalik.
Sintaks pipa adalah IMO yang paling mudah dibaca, mengingat infiksnya. Pembaruan perpustakaan Boost.Range menunggu tinjauan mengimplementasikan ini, tetapi cukup mudah untuk melakukannya sendiri juga. Bahkan lebih keren dengan lambda DSEL untuk menghasilkan fungsi f dan predikat p in-line.
sumber
sumber
Saya lebih suka loop sementara. Ini lebih jelas bagi saya daripada mengurangi
i
dalam kondisi loop forsumber
Saya akan menggunakan kode di pertanyaan awal, tetapi jika Anda benar-benar ingin menggunakan foreach dan memiliki indeks integer di C #:
sumber
Saya akan mencoba menjawab pertanyaan saya sendiri di sini, tetapi saya juga tidak terlalu suka ini:
sumber
CATATAN: Posting ini akhirnya menjadi jauh lebih rinci dan karena itu keluar dari topik, saya minta maaf.
Itu dikatakan rekan-rekan saya membacanya dan percaya itu berharga 'di suatu tempat'. Utas ini bukan tempatnya. Saya sangat menghargai umpan balik Anda tentang ke mana ini harus pergi (saya baru di situs ini).
Bagaimanapun ini adalah versi C # di .NET 3.5 yang luar biasa karena ia bekerja pada semua jenis koleksi menggunakan semantik yang ditentukan. Ini adalah ukuran default (gunakan kembali!), Bukan kinerja atau minimalisasi siklus CPU dalam skenario dev yang paling umum meskipun tampaknya tidak pernah terjadi di dunia nyata (pengoptimalan prematur).
*** Metode ekstensi bekerja pada semua jenis koleksi dan mengambil delegasi tindakan yang mengharapkan satu nilai dari jenis tersebut, semuanya dijalankan secara terbalik pada setiap item **
Requres 3.5:
Versi .NET yang lebih lama atau Anda ingin memahami internal Linq dengan lebih baik? Baca terus .. Atau tidak ..
ASUMSI: Dalam sistem tipe .NET, tipe Array mewarisi dari antarmuka IEnumerable (bukan IEnumerable generik hanya IEnumerable).
Ini semua yang Anda butuhkan untuk mengulang dari awal hingga akhir, namun Anda ingin bergerak ke arah yang berlawanan. Karena IEnumerable bekerja pada Array tipe 'objek', tipe apa pun valid,
TINDAKAN KRITIS: Kami berasumsi jika Anda dapat memproses urutan apa pun dalam urutan terbalik yang 'lebih baik' maka hanya dapat melakukannya pada bilangan bulat.
Solusi a untuk .NET CLR 2.0-3.0:
Deskripsi: Kami akan menerima semua contoh implementasi IEnumerable dengan mandat bahwa setiap contoh yang dikandungnya adalah dari jenis yang sama. Jadi jika kita menerima sebuah array, seluruh array berisi instance tipe X. Jika ada instance lain yang bertipe! = X pengecualian dilemparkan:
Layanan tunggal:
public class ReverserService {private ReverserService () {}
[TestFixture] kelas publik Testing123 {
sumber