Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: fortran1986 10. 01. 2021, 22:40:46
-
Mám funkciu filesystem::directory_iterator (https://en.cppreference.com/w/cpp/filesystem/directory_iterator) ktorá vracia všetky filesystem entries vrátane files, directories, symlinky a rôzne zariadenia etc.
a ja by som si chcel spraviť 2 helper funkcie:
jedna sa bude volať directory::contained_files vracajúca len súbory vo folderi a druhá directory::contained_directories vracajúca len foldre.
Ale chcem aby to vracalo zase iterátor (nie kontainer ale iterátor)
viem že v directory_entry má funkcie ktoré vrátia boolean pri is_directory alebo is_regular_file ale ako vrátiť znovu iterátor? V iných jazykoch by som tam hodil cyklus a pri generátoroch a urobil yield alebo použil Seq.filter či LINQ where Ale C++ má korutiny (https://en.cppreference.com/w/cpp/language/coroutines) až od verize 20 a tá ešte neni hotová. V mojej preview verzii C++ 20 zatiaľ neni ani typ generator<item_name> ani co_yield takže ako to by som to mal riešiť bez korutín?
-
Podľa toho čo vidím v zdrojáku directory_iteratora tak by som si asi musel napísať vlastný iterátor.
-
Pro zajímavost, v Rustu se to dělá idiomaticky bez korutin i bez implementace vlastního iterátoru. Když už mám iterátor, a chci z něj jen vyfiltrovat některé položky, použiju prostě metodu filter, která vrací jiný iterátor. Ten má v sobě zabalený ten původní a predikát, při iteraci přeskakuje nevyhovující.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c93f0ee782a56a5e475f6e26c95229f3
fn filter_files(iter: impl Iterator<Item=String>) -> impl Iterator<Item=String> {
iter.filter(|item| item.starts_with("Soubor"))
}
fn main() {
let v = vec!["Soubor XXX".to_string(), "Adresar YYY".to_string()];
for s in filter_files(v.into_iter()) {
println!("{}", s)
}
}
vypíše Soubor XXX.
-
V C++ se na to hodí https://en.cppreference.com/w/cpp/ranges (https://en.cppreference.com/w/cpp/ranges).
Případně použít boost:
https://www.boost.org/doc/libs/1_75_0/libs/range/doc/html/index.html (https://www.boost.org/doc/libs/1_75_0/libs/range/doc/html/index.html)
https://www.boost.org/doc/libs/1_75_0/libs/iterator/doc/index.html (https://www.boost.org/doc/libs/1_75_0/libs/iterator/doc/index.html)
-
Pro zajímavost, v Rustu se to dělá idiomaticky bez korutin i bez implementace vlastního iterátoru. Když už mám iterátor, a chci z něj jen vyfiltrovat některé položky, použiju prostě metodu filter, která vrací jiný iterátor. Ten má v sobě zabalený ten původní a predikát, při iteraci přeskakuje nevyhovující.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c93f0ee782a56a5e475f6e26c95229f3
fn filter_files(iter: impl Iterator<Item=String>) -> impl Iterator<Item=String> {
iter.filter(|item| item.starts_with("Soubor"))
}
fn main() {
let v = vec!["Soubor XXX".to_string(), "Adresar YYY".to_string()];
for s in filter_files(v.into_iter()) {
println!("{}", s)
}
}
vypíše Soubor XXX.
Hej implementovať vlastný iterátor nemusíte, lebo ho už pred vami implemetovali programátri rustovského ekosystému. filter vracia špeciálny iterátor s názvom Filter (https://doc.rust-lang.org/nightly/src/core/iter/adapters/filter.rs.html) a ten je natoľko obecný (keďže obsahuje predikát) že sa dá použiť všade kde sa niečo filtruje, aspoň teda ak správne čítam zdroják:
url=https://doc.rust-lang.org/nightly/src/core/iter/adapters/filter.rs.html
Podobne to funguje aj v LINQ (v C# a F#) cca 15 rokov: Seq.filter (https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-seqmodule.html#filter) a (F#)Enumerable.Where (https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where) (C#) vracaju WhereEnumerableIterator a WhereIterator. Tu je zdroják... funkcia filter Where je hneď na začiatku:
Edit: nie filter ale Where pletie sa mi to lebo Seq.filter je vlastne alias pre Enumerable.Where a Seq.map je niečo ako alias pre Enumerable.Select
https://referencesource.microsoft.com/#system.core/system/linq/Enumerable.cs
Mimochodom aj v java to má podobne (odkedy tam pridali streamy)
Aj STL či boost má funkcie z rovnakého súdka napr std::copy_if je náhrada za filter a std::transform náhrada za map etc aj keď iterárátormi sa tam pracuje o niečo krkolomnejšie používajú sa tam insertery a podobne, ale zase sa to dá aj viac customizovať. Ja som pre C++ hľadal niečo viac sexy, čo funguje podobne ako váš príklad z Rustu. Akurát C++ je veľmi konzervatívny jazyk, ktorý pridáva nové vlastnosti pomaly a to až vtedy keď su poriadne odstestované naprieč ostatnými jazykmi. Nepozerá až tak veľmi na sexy zápis, ale skôr performance. A keď sa tam má dostať nejaká nová vlastnosť tak až vtedy keď sa navrhne nejaká veľmi efektívna a dokonale customizovateľná univerzálna implemetácia.
Ale inak ďakujem za vysvetlenie :) Rust je jeden z jazykov, ktorý má do budúcna potenciál možno raz aj nahradiť C/C++
-
V C++ se na to hodí https://en.cppreference.com/w/cpp/ranges (https://en.cppreference.com/w/cpp/ranges).
Případně použít boost:
https://www.boost.org/doc/libs/1_75_0/libs/range/doc/html/index.html (https://www.boost.org/doc/libs/1_75_0/libs/range/doc/html/index.html)
https://www.boost.org/doc/libs/1_75_0/libs/iterator/doc/index.html (https://www.boost.org/doc/libs/1_75_0/libs/iterator/doc/index.html)
Ďakujem pozriem.
-
Pro zajímavost, v Rustu se to dělá idiomaticky bez korutin i bez implementace vlastního iterátoru. Když už mám iterátor, a chci z něj jen vyfiltrovat některé položky, použiju prostě metodu filter, která vrací jiný iterátor. Ten má v sobě zabalený ten původní a predikát, při iteraci přeskakuje nevyhovující.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c93f0ee782a56a5e475f6e26c95229f3
fn filter_files(iter: impl Iterator<Item=String>) -> impl Iterator<Item=String> {
iter.filter(|item| item.starts_with("Soubor"))
}
fn main() {
let v = vec!["Soubor XXX".to_string(), "Adresar YYY".to_string()];
for s in filter_files(v.into_iter()) {
println!("{}", s)
}
}
vypíše Soubor XXX.
Hej implementovať vlastný iterátor nemusíte, lebo ho už pred vami implemetovali programátri rustovského ekosystému. filter vracia špeciálny iterátor s názvom Filter (https://doc.rust-lang.org/nightly/src/core/iter/adapters/filter.rs.html) ...
Jasně, vždyť přesně to můj příklad dělá :-) filter_files vrací Filter, akorát že ten Filter je tu maskovaný pod typem impl Iterator<Item=...>, abych se nemusel s tím typem vypisovat, a taky v budoucnu umožnil eventuelní změnu implementace bez narušení kompatibility typů funkce..
-
Pro zajímavost, v Rustu se to dělá idiomaticky bez korutin i bez implementace vlastního iterátoru. Když už mám iterátor, a chci z něj jen vyfiltrovat některé položky, použiju prostě metodu filter, která vrací jiný iterátor. Ten má v sobě zabalený ten původní a predikát, při iteraci přeskakuje nevyhovující.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c93f0ee782a56a5e475f6e26c95229f3
fn filter_files(iter: impl Iterator<Item=String>) -> impl Iterator<Item=String> {
iter.filter(|item| item.starts_with("Soubor"))
}
fn main() {
let v = vec!["Soubor XXX".to_string(), "Adresar YYY".to_string()];
for s in filter_files(v.into_iter()) {
println!("{}", s)
}
}
vypíše Soubor XXX.
Hej implementovať vlastný iterátor nemusíte, lebo ho už pred vami implemetovali programátri rustovského ekosystému. filter vracia špeciálny iterátor s názvom Filter (https://doc.rust-lang.org/nightly/src/core/iter/adapters/filter.rs.html) ...
Jasně, vždyť přesně to můj příklad dělá :-) filter_files vrací Filter, akorát že ten Filter je tu maskovaný pod typem impl Iterator<Item=...>, abych se nemusel s tím typem vypisovat, a taky v budoucnu umožnil eventuelní změnu implementace bez narušení kompatibility typů funkce..
Jasné chápem