Saya tahu saya bisa menggunakan for
pernyataan dan mencapai efek yang sama, tetapi bisakah saya memutar mundur melalui foreach
loop di C #?
IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }
Bagaimana Anda membalikkan itu?
Saya tahu saya bisa menggunakan for
pernyataan dan mencapai efek yang sama, tetapi bisakah saya memutar mundur melalui foreach
loop di C #?
IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }
Bagaimana Anda membalikkan itu?
Jawaban:
Ketika bekerja dengan daftar (pengindeksan langsung), Anda tidak dapat melakukannya seefisien menggunakan for
loop.
Sunting: Yang secara umum berarti, ketika Anda dapat menggunakan for
perulangan, kemungkinan metode yang tepat untuk tugas ini. Plus, sebanyak foreach
diterapkan dalam urutan, konstruksi itu sendiri dibangun untuk mengekspresikan loop yang independen dari indeks elemen dan urutan iterasi, yang sangat penting dalam pemrograman paralel . Ini adalah pendapat saya bahwa iterasi mengandalkan agar tidak harus menggunakan foreach
untuk perulangan.
yield return
".
Jika Anda menggunakan .NET 3.5, Anda dapat melakukan ini:
IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())
Ini tidak terlalu efisien karena pada dasarnya harus melalui pencacah ke depan meletakkan segala sesuatu di atas tumpukan kemudian muncul semuanya kembali dalam urutan terbalik.
Jika Anda memiliki koleksi yang dapat diindeks secara langsung (mis. IList), Anda harus menggunakan for
loop.
Jika Anda menggunakan .NET 2.0 dan tidak dapat menggunakan for loop (yaitu Anda hanya memiliki IEnumerable) maka Anda hanya perlu menulis fungsi Reverse Anda sendiri. Ini seharusnya bekerja:
static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
return new Stack<T>(input);
}
Ini bergantung pada beberapa perilaku yang mungkin tidak terlalu jelas. Ketika Anda melewati sebuah IEnumerable ke konstruktor stack itu akan beralih melalui itu dan mendorong item ke tumpukan. Ketika Anda kemudian beralih melalui tumpukan itu muncul hal-hal kembali dalam urutan terbalik.
Ini dan Reverse()
metode ekstensi .NET 3.5 jelas akan meledak jika Anda memberinya IEnumerable yang tidak pernah berhenti mengembalikan item.
Seperti yang dikatakan 280Z28, IList<T>
Anda hanya bisa menggunakan indeks. Anda dapat menyembunyikan ini dalam metode ekstensi:
public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
for (int i = items.Count-1; i >= 0; i--)
{
yield return items[i];
}
}
Ini akan lebih cepat daripada Enumerable.Reverse()
yang buffer semua data terlebih dahulu. (Saya tidak yakin Reverse
ada optimasi yang diterapkan seperti itu Count()
.) Perhatikan bahwa buffering ini berarti bahwa data dibaca sepenuhnya ketika Anda pertama kali memulai iterasi, sedangkan FastReverse
akan "melihat" setiap perubahan yang dibuat ke daftar saat Anda iterate. (Ini juga akan pecah jika Anda menghapus beberapa item di antara iterasi.)
Untuk urutan umum, tidak ada cara untuk mengulang secara terbalik - urutannya bisa tak terbatas, misalnya:
public static IEnumerable<T> GetStringsOfIncreasingSize()
{
string ret = "";
while (true)
{
yield return ret;
ret = ret + "x";
}
}
Apa yang Anda harapkan terjadi jika Anda mencoba mengulanginya secara terbalik?
Sebelum menggunakan foreach
untuk iterasi, balikkan daftar dengan reverse
metode:
myList.Reverse();
foreach( List listItem in myList)
{
Console.WriteLine(listItem);
}
myList
yang akan membantu. IEnumerable.Reverse tidak bekerja di sini.
myList
tampaknya bertipe System.Collections.Generic.List<System.Windows.Documents.List>
(atau List
jenis kustom lainnya ) kalau tidak, kode ini tidak berfungsi: P
Kadang-kadang Anda tidak memiliki kemewahan pengindeksan, atau mungkin Anda ingin membalikkan hasil kueri Linq, atau mungkin Anda tidak ingin mengubah kumpulan sumber, jika ada yang benar, Linq dapat membantu Anda.
Metode ekstensi Linq menggunakan tipe anonim dengan Linq Select untuk memberikan kunci penyortiran untuk Linq OrderByDescending;
public static IEnumerable<T> Invert<T>(this IEnumerable<T> source)
{
var transform = source.Select(
(o, i) => new
{
Index = i,
Object = o
});
return transform.OrderByDescending(o => o.Index)
.Select(o => o.Object);
}
Pemakaian:
var eable = new[]{ "a", "b", "c" };
foreach(var o in eable.Invert())
{
Console.WriteLine(o);
}
// "c", "b", "a"
Itu bernama "Balikkan" karena ini identik dengan "Balikkan" dan memungkinkan disambiguasi dengan implementasi Daftar Balikkan.
Dimungkinkan untuk membalikkan rentang koleksi tertentu juga, karena Int32.MinValue dan Int32.MaxValue berada di luar kisaran jenis indeks pengumpulan apa pun, kami dapat memanfaatkannya untuk proses pemesanan; jika indeks elemen di bawah rentang yang diberikan, itu diberikan Int32.MaxValue sehingga pesanannya tidak berubah saat menggunakan OrderByDescending, sama halnya, elemen pada indeks yang lebih besar dari rentang yang diberikan, akan diberikan Int32.MinValue, sehingga mereka muncul di akhir proses pemesanan. Semua elemen dalam rentang yang diberikan diberi indeks normal dan dibalik sesuai.
public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count)
{
var transform = source.Select(
(o, i) => new
{
Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i,
Object = o
});
return transform.OrderByDescending(o => o.Index)
.Select(o => o.Object);
}
Pemakaian:
var eable = new[]{ "a", "b", "c", "d" };
foreach(var o in eable.Invert(1, 2))
{
Console.WriteLine(o);
}
// "a", "c", "b", "d"
Saya tidak yakin dengan kinerja hit implementasi Linq ini versus menggunakan Daftar sementara untuk membungkus koleksi untuk dibalik.
Pada saat penulisan, saya tidak mengetahui implementasi Reverse Linq sendiri, tetap saja, ini sangat menyenangkan. https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx
Jika Anda menggunakan Daftar <T>, Anda juga dapat menggunakan kode ini:
List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();
Ini adalah metode yang menulis daftar terbalik dengan sendirinya.
Sekarang kedepan:
foreach(string s in list)
{
Console.WriteLine(s);
}
Outputnya adalah:
3
2
1
Hal ini mungkin jika Anda dapat mengubah kode koleksi yang menerapkan IEnumerable atau IEnumerable (misalnya implementasi sendiri dari IList).
Buat Iterator melakukan pekerjaan ini untuk Anda, misalnya seperti implementasi berikut melalui antarmuka IEnumerable (dengan asumsi 'item' adalah bidang Daftar dalam sampel ini):
public IEnumerator<TObject> GetEnumerator()
{
for (var i = items.Count - 1; i >= 0; i--)
{
yield return items[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
Karena ini Daftar Anda akan diulang dalam urutan terbalik melalui daftar Anda.
Sekedar petunjuk: Anda harus dengan jelas menyatakan perilaku khusus dari daftar ini di dalam dokumentasi (bahkan lebih baik dengan memilih nama kelas yang menjelaskan sendiri seperti Stack atau Queue, juga).
Tidak. ForEach hanya mengulang melalui pengumpulan untuk setiap item dan pesanan tergantung apakah ia menggunakan IEnumerable atau GetEnumerator ().
Menguraikan sedikit tentang jawaban yang bagus dari Jon Skeet , ini bisa serbaguna:
public static IEnumerable<T> Directional<T>(this IList<T> items, bool Forwards) {
if (Forwards) foreach (T item in items) yield return item;
else for (int i = items.Count-1; 0<=i; i--) yield return items[i];
}
Dan kemudian gunakan sebagai
foreach (var item in myList.Directional(forwardsCondition)) {
.
.
}
Saya telah menggunakan kode ini yang berfungsi
if (element.HasAttributes) {
foreach(var attr in element.Attributes().Reverse())
{
if (depth > 1)
{
elements_upper_hierarchy_text = "";
foreach (var ancest in element.Ancestors().Reverse())
{
elements_upper_hierarchy_text += ancest.Name + "_";
}// foreach(var ancest in element.Ancestors())
}//if (depth > 1)
xml_taglist_report += " " + depth + " " + elements_upper_hierarchy_text+ element.Name + "_" + attr.Name +"(" + attr.Name +")" + " = " + attr.Value + "\r\n";
}// foreach(var attr in element.Attributes().Reverse())
}// if (element.HasAttributes) {
.Reverse()
sebenarnya memodifikasi daftar.
Ini bekerja dengan cukup baik
List<string> list = new List<string>();
list.Add("Hello");
list.Add("Who");
list.Add("Are");
list.Add("You");
foreach (String s in list)
{
Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]);
}