Как получить итератор для элемента максимального значения в Rust? - PullRequest
0 голосов
/ 25 сентября 2019

Я хочу получить доступ к элементу рядом с максимальным в Vec<i32>.Я ищу что-то вроде этого:

let v = vec![1, 3, 2];
let it = v.iter().max_element();
assert_eq!(Some(&2), it.next());

В C ++ я бы выбрал std::max_element, а затем просто увеличил итератор (с проверкой границ или без нее, в зависимости от того, насколько авантюрным я себя сейчас чувствую).Rust max возвращает только ссылку на элемент, что недостаточно для моего варианта использования.

Единственное решение, которое я придумал, - это использование enumerate для получения индекса элемента, но это кажется ручным и громоздким по сравнению с методом C ++.

Я бы предпочел что-то встандартная библиотека.

Этот пример упрощен - я на самом деле хочу прикрепить к наибольшему значению, а затем из этой точки цикла по всему контейнеру (возможно, с cycle() или что-то подобное).

Ответы [ 2 ]

3 голосов
/ 25 сентября 2019

C ++ итераторы не совпадают с итераторами Rust.Итераторы Rust предназначены только для пересылки и могут быть пройдены только один раз.Итераторы C ++ можно рассматривать как курсоры.См. Каковы основные различия между итератором Rust и итератором C ++? для получения более подробной информации.

Чтобы достичь цели наиболее общим способом, вам нужно пройти весь итератор, чтобы найти максимальное значение.Попутно вам придется дублировать итератор каждый раз, когда вы найдете новое максимальное значение.В конце вы можете вернуть итератор, соответствующий точке после максимального значения.

trait MaxElement {
    type Iter;

    fn max_element(self) -> Self::Iter;
}

impl<I> MaxElement for I
where
    I: Iterator + Clone,
    I::Item: PartialOrd,
{
    type Iter = Self;

    fn max_element(mut self) -> Self::Iter {
        let mut max_iter = self.clone();
        let mut max_val = None;

        while let Some(val) = self.next() {
            if max_val.as_ref().map_or(true, |m| &val > m) {
                max_iter = self.clone();
                max_val = Some(val);
            }
        }

        max_iter
    }
}

fn main() {
    let v = vec![1, 3, 2];
    let mut it = v.iter().max_element();
    assert_eq!(Some(&2), it.next());
}

См. Также:

Я действительно хочу прикрепить к наибольшему значению, а затем из этой точки зациклить весь контейнер (возможно, с cycle() или чем-то подобным).1021 *

В этом случае я бы попытался быть более очевидным:

fn index_of_max(values: &[i32]) -> Option<usize> {
    values
        .iter()
        .enumerate()
        .max_by_key(|(_idx, &val)| val)
        .map(|(idx, _val)| idx)
}

fn main() {
    let v = vec![1, 3, 2];
    let idx = index_of_max(&v).unwrap_or(0);
    let (a, b) = v.split_at(idx);
    let mut it = b.iter().chain(a).skip(1);
    assert_eq!(Some(&2), it.next());
}

См. Также:

1 голос
/ 26 сентября 2019

Если все, что вам нужно, это значение элемента, следующего за максимумом, я бы сделал это простым вызовом fold, отслеживая найденный максимум и соответствующее следующее значение:

fn main() {
    let v = vec![1, 3, 2];
    let nxt = v.iter().fold (
        (None, None),
        |acc, x| {
            match acc {
                (Some (max), _) if x > max => (Some (x), None),
                (Some (max), None) => (Some (max), Some (x)),
                (None, _) => (Some (x), None),
                _ => acc
            }
        }
    ).1;
    assert_eq!(Some(&2), nxt);
}

детская площадка

В зависимости от того, что вы хотите сделать с предметами, следующими за максимумом, подобный подход может позволить вам сделать это за один проход.

...