Jadi saya punya pohon sederhana:
class MyNode
{
public MyNode Parent;
public IEnumerable<MyNode> Elements;
int group = 1;
}
Saya punya IEnumerable<MyNode>
. Saya ingin mendapatkan daftar semua MyNode
(termasuk objek simpul dalam ( Elements
)) sebagai satu daftar datar Where
group == 1
. Bagaimana cara melakukan hal seperti itu melalui LINQ?
Elements
nol atau kosong?Jawaban:
Anda bisa meratakan pohon seperti ini:
Anda kemudian dapat memfilter dengan
group
menggunakanWhere(...)
.Untuk mendapatkan beberapa "poin untuk gaya", konversikan
Flatten
ke fungsi ekstensi di kelas statis.Untuk mendapatkan lebih banyak poin untuk "gaya yang lebih baik", konversikan
Flatten
ke metode ekstensi umum yang menggunakan pohon dan fungsi yang menghasilkan turunan dari node:Panggil fungsi ini seperti ini:
Jika Anda lebih suka meratakan dalam pre-order daripada post-order, ganti di sekitar sisi
Concat(...)
.sumber
Concat
harusnew[] {e}
, bukannew[] {c}
(bahkan tidak akan dikompilasi dic
sana).c
. Menggunakane
tidak dapat dikompilasi. Anda juga dapat menambahkanif (e == null) return Enumerable.Empty<T>();
untuk mengatasi daftar anak nol.Masalah dengan jawaban yang diterima adalah tidak efisien jika pohonnya dalam. Jika pohonnya sangat dalam maka tumpukan itu akan meledak. Anda dapat memecahkan masalah dengan menggunakan tumpukan eksplisit:
Dengan asumsi n node dalam pohon dengan tinggi h dan faktor percabangan jauh lebih kecil dari n, metode ini adalah O (1) dalam ruang stack, O (h) dalam ruang heap dan O (n) dalam waktu. Algoritma lain yang diberikan adalah O (h) di stack, O (1) di heap dan O (nh) di waktu. Jika faktor percabangan kecil dibandingkan dengan n maka h berada di antara O (lg n) dan O (n), yang menggambarkan bahwa algoritma naïve dapat menggunakan jumlah stack yang berbahaya dan waktu yang banyak jika h mendekati n.
Sekarang setelah kami memiliki traversal, kueri Anda sangat mudah:
sumber
Traverse
semua elemen. Atau Anda dapat memodifikasiTraverse
untuk mengambil urutan, dan membuatnya mendorong semua elemen urutan ke atasstack
. Ingat,stack
adalah "elemen yang belum saya lintasi". Atau Anda bisa membuat root "dummy" di mana urutan Anda adalah anak-anaknya, dan kemudian melintasi root dummy.foreach (var child in current.Elements.Reverse())
Anda akan mendapatkan perataan yang lebih diharapkan. Secara khusus, anak-anak akan muncul dalam urutan kemunculannya, bukan anak terakhir yang pertama. Ini seharusnya tidak menjadi masalah dalam banyak kasus, tetapi dalam kasus saya, saya membutuhkan perataan dalam urutan yang dapat diprediksi dan diharapkan..Reverse
dengan menukarStack<T>
untuk aQueue<T>
Reverse
adalah hal itu membuat iterator tambahan, yang dimaksudkan untuk dihindari oleh pendekatan ini. @RubensFarias MenggantiQueue
untukStack
hasil dalam traversal luas-pertama.Sekadar kelengkapan, berikut kombinasi jawaban dari dasblinkenlight dan Eric Lippert. Unit diuji dan semuanya. :-)
sumber
Memperbarui:
Untuk orang yang tertarik dengan level nesting (kedalaman). Salah satu hal baik tentang implementasi tumpukan enumerator eksplisit adalah bahwa setiap saat (dan khususnya saat menghasilkan elemen)
stack.Count
mewakili kedalaman pemrosesan saat ini. Jadi dengan mempertimbangkan hal ini dan memanfaatkan tupel nilai C # 7.0, kita cukup mengubah deklarasi metode sebagai berikut:dan
yield
pernyataan:Kemudian kita dapat mengimplementasikan metode asli dengan menerapkan simple
Select
di atas:Asli:
Anehnya tidak ada (bahkan Eric) yang menunjukkan port berulang "alami" dari DFT pra-order rekursif, jadi ini dia:
sumber
e
setiap kali Anda meneleponelementSelector
untuk mempertahankan pesanan di muka - jika pesanan tidak penting, dapatkah Anda mengubah fungsi untuk memproses semuanyae
setelah dimulai?Queue<T>
. Bagaimanapun, idenya di sini adalah untuk menyimpan tumpukan kecil dengan enumerator, sangat mirip dengan apa yang terjadi dalam implementasi rekursif.Stack
akan menghasilkan Traversal Pertama Breadth zig-zag.Saya menemukan beberapa masalah kecil dengan jawaban yang diberikan di sini:
Dibangun di atas jawaban sebelumnya dan muncul dengan yang berikut:
Dan tes unit:
sumber
Jika ada orang lain yang menemukan ini, tetapi juga perlu mengetahui level setelah mereka meratakan pohon, ini memperluas kombinasi dasblinkenlight dan solusi Eric Lippert dari Konamiman:
sumber
Pilihan lain adalah memiliki desain OO yang tepat.
mis. minta
MyNode
untuk mengembalikan semua rata.Seperti ini:
Sekarang Anda dapat meminta MyNode tingkat atas untuk mendapatkan semua node.
Jika Anda tidak dapat mengedit kelas, ini bukanlah pilihan. Tetapi sebaliknya, saya pikir ini bisa lebih disukai dari metode LINQ (rekursif) terpisah.
Ini menggunakan LINQ, Jadi saya pikir jawaban ini dapat diterapkan di sini;)
sumber
sumber
Menggabungkan jawaban Dave dan Ivan Stoev seandainya Anda membutuhkan level bersarang dan daftarnya diratakan "dalam urutan" dan tidak terbalik seperti pada jawaban yang diberikan oleh Konamiman.
sumber
Berdasarkan jawaban Konamiman, dan komentar bahwa urutannya tidak terduga, berikut adalah versi dengan parameter sortir eksplisit:
Dan contoh penggunaan:
sumber
Di bawah ini adalah kode Ivan Stoev dengan fitur tambahan yang memberi tahu indeks setiap objek di jalur. Misalnya, telusuri "Item_120":
akan mengembalikan item dan array int [1,2,0]. Jelas, level bersarang juga tersedia, sebagai panjang array.
sumber
Di sini beberapa implementasi siap menggunakan menggunakan Antrian dan mengembalikan pohon Ratakan saya terlebih dahulu dan kemudian anak-anak saya.
sumber
Sesekali saya mencoba untuk mengatasi masalah ini dan merancang solusi saya sendiri yang mendukung struktur dalam sewenang-wenang (tidak ada rekursi), melakukan traversal pertama yang luas, dan tidak menyalahgunakan terlalu banyak kueri LINQ atau melakukan rekursi lebih dulu pada anak-anak. Setelah menggali di sekitar sumber .NET dan mencoba banyak solusi, saya akhirnya menemukan solusi ini. Itu akhirnya menjadi sangat dekat dengan jawaban Ian Stoev (yang jawabannya baru saja saya lihat), namun saya tidak menggunakan loop tak terbatas atau memiliki aliran kode yang tidak biasa.
Contoh yang berfungsi dapat ditemukan di sini .
sumber