Iterator::take_while în Rust

take_while dă elemente cât timp condiția e adevărată și se oprește la primul care nu o îndeplinește; skip_while sare până atunci.

Sintaxă
fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
fn skip_while<P>(self, predicate: P) -> SkipWhile<Self, P>
where P: FnMut(&Self::Item) -> bool

Ce face Iterator::take_while

take_while(|x| cond) produce elemente până la primul pentru care condiția este falsă, apoi se oprește definitiv, chiar dacă mai târziu ar urma elemente care o îndeplinesc. skip_while(|x| cond) face complementul: sare peste elemente cât timp condiția e adevărată, apoi le dă pe toate celelalte, fără să mai verifice condiția.

Diferența față de filter: filter verifică fiecare element; take_while și skip_while privesc doar „începutul” șirului. Sunt potrivite pentru date sortate sau pentru prefixe (cifrele de la începutul unui text, liniile de antet). Ca la filter, closure-ul primește o referință. Ca toate adaptoarele, este leneș: nu face nimic până când iteratorul nu este consumat (de for, collect, sum, count etc.).

Parametri

Parametru Descriere
predicate Condiția verificată pe &element.

Ce returnează

Un iterator TakeWhile sau SkipWhile.

Exemple

Exemplul 1: Comparație cu filter

take_while se oprește la 12, deci nu ajunge la 3 și 4 de la final; filter îi găsește.

fn main() {
    let v = [1, 4, 7, 12, 3, 4];
    let tw: Vec<i32> = v.iter().copied().take_while(|&x| x < 10).collect();
    let sw: Vec<i32> = v.iter().copied().skip_while(|&x| x < 10).collect();
    let f: Vec<i32> = v.iter().copied().filter(|&x| x < 10).collect();
    println!("take_while: {:?}", tw);
    println!("skip_while: {:?}", sw);
    println!("filter:     {:?}", f);
}

Rezultat

take_while: [1, 4, 7]
skip_while: [12, 3, 4]
filter:     [1, 4, 7, 3, 4]

Exemplul 2: Numărul de la începutul unui text

fn main() {
    for text in ["42 de elevi", "7kg", "fără număr"] {
        let cifre: String = text.chars().take_while(|c| c.is_ascii_digit()).collect();
        let rest: String = text.chars().skip_while(|c| c.is_ascii_digit()).collect();
        println!("{text:12} -> număr: {:?}, rest: {:?}", cifre, rest.trim());
    }
}

Rezultat

42 de elevi  -> număr: "42", rest: "de elevi"
7kg          -> număr: "7", rest: "kg"
fără număr   -> număr: "", rest: "fără număr"

Exemplul 3: Comenzi de azi dintr-o listă sortată după oră

fn main() {
    // (ora, client), sortate după oră
    let comenzi = [(8, "Ana"), (9, "Mihai"), (11, "Ioana"), (14, "Radu"), (17, "Elena")];
    let dimineata: Vec<&str> = comenzi.iter().take_while(|(ora, _)| *ora < 12).map(|(_, c)| *c).collect();
    let dupa_amiaza: Vec<&str> = comenzi.iter().skip_while(|(ora, _)| *ora < 12).map(|(_, c)| *c).collect();
    println!("dimineața: {:?}", dimineata);
    println!("după-amiaza: {:?}", dupa_amiaza);
}

Rezultat

dimineața: ["Ana", "Mihai", "Ioana"]
după-amiaza: ["Radu", "Elena"]

Greșeli frecvente

  • Folosești take_while pe date nesortate și te aștepți să găsească toate elementele care îndeplinesc condiția. Se oprește la primul care nu o îndeplinește; pentru toate folosește filter.
  • Elementul care oprește take_while este consumat din sursă și pierdut. Dacă îl vrei înapoi, folosește peekable() cu next_if.

Comenzi înrudite

  • Iterator::take: take(n) produce cel mult primele n elemente; skip(n) sare peste primele n și produce restul.
  • Iterator::map_while: Transformă elementele cât timp funcția returnează Some și se oprește la primul None.
  • Iterator::filter: Păstrează doar elementele pentru care condiția dată returnează true; restul sunt sărite.
  • Iterator::peekable: Transformă iteratorul într-un Peekable, care te lasă să te uiți la următorul element (peek) fără să-l consumi.
  • BTreeSet::range: Parcurge doar elementele dintr-un interval de valori, în ordine; util pentru „următorul după x” sau „toate dintre a și b”.