Каков идиоматический способ получить индекс максимального или минимального значения с плавающей запятой в срезе или Vec в Rust? - PullRequest
0 голосов
/ 23 декабря 2018

Предположение - Vec<f32> не не имеет какие-либо значения NaN или проявляет какое-либо поведение NaN.

Возьмите следующий набор образцов:

0.28  
0.3102
0.9856
0.3679
0.3697
0.46  
0.4311
0.9781
0.9891
0.5052
0.9173
0.932 
0.8365
0.5822
0.9981
0.9977

Какой самый удобный и стабильный способ получить index самого высокого значения в приведенном выше списке (значения могут быть отрицательными)?

Мои первые попытки были следующими:

let _tmp = *nets.iter().max_by(|i, j| i.partial_cmp(j).unwrap()).unwrap();    
let _i = nets.iter().position(|&element| element == _tmp).unwrap();

Где nets - это &Vec<f32>.Что мне кажется явно неверным.

Python-эквивалент этого, который работает (с учетом вышеизложенного предположения):

_i = nets.index(max(nets))

Ответы [ 4 ]

0 голосов
/ 24 декабря 2018

Есть ли причина, по которой это не сработает?

use std::cmp::Ordering;

fn example(nets: &Vec<f32>) {
    let index_of_max: Option<usize> = nets
        .iter()
        .enumerate()
        .max_by(|(_, a), (_, b)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
        .map(|(index, _)| index);
}
0 голосов
/ 23 декабря 2018

Я, вероятно, сделаю что-то вроде этого:

fn main() -> Result<(), Box<std::error::Error>> {
    let samples = vec![
        0.28, 0.3102, 0.9856, 0.3679, 0.3697, 0.46, 0.4311, 0.9781, 0.9891, 0.5052, 0.9173, 0.932,
        0.8365, 0.5822, 0.9981, 0.9977,
    ];

    // Use enumerate to get the index
    let mut iter = samples.iter().enumerate();
    // we get the first entry
    let init = iter.next().ok_or("Need at least one input")?;
    // we process the rest
    let result = iter.try_fold(init, |acc, x| {
        // return None if x is NaN
        let cmp = x.1.partial_cmp(acc.1)?;
        // if x is greater the acc
        let max = if let std::cmp::Ordering::Greater = cmp {
            x
        } else {
            acc
        };
        Some(max)
    });
    println!("{:?}", result);

    Ok(())
}

Это можно реализовать, добавив черту в Iterator, например, с помощью функции try_max_by.

0 голосов
/ 23 декабря 2018

Причина, по которой это сложно, заключается в том, что f32 не реализует Ord.Это связано с тем, что значения NaN препятствуют формированию общего порядка чисел с плавающей запятой, что нарушает контракт Ord.

. Существуют ящики сторонних производителей, которые обходят это путем определения обертки числового типа, которая не являетсяразрешено содержать NaN.Одним из примеров является orders-float .Если вы используете этот ящик, чтобы сначала подготовить коллекцию, содержащую NotNan значений, то вы можете написать код, очень близкий к исходной идее:

use ordered_float::NotNan;

let non_nan_floats: Vec<_> = nets.iter()
    .cloned()
    .map(NotNan::new)       // Attempt to convert each f32 to a NotNan
    .filter_map(Result::ok) // Unwrap the `NotNan`s and filter out the `NaN` values 
    .collect();

let max = non_nan_floats.iter().max().unwrap();
let index = non_nan_floats.iter().position(|element| element == max).unwrap();

Добавьте это к Cargo.toml:

[dependencies]
ordered-float = "1.0.1"

Бонусный материал : преобразование типов может быть сделано по-настоящему без затрат (при условии, что вы действительно уверены, что нет NaN значения!), используя тот факт, что NotNan имеет прозрачное представление:

let non_nan_floats: Vec<NotNan<f32>> = unsafe { mem::transmute(nets) };
0 голосов
/ 23 декабря 2018

Вы можете найти максимальное значение следующим образом:

let mut max_value = my_vec.iter().fold(0.0f32, |mut max, &val| {
    if val > max {
        max = val;
    }
    max
});

После нахождения max_value вы можете отслеживать его положение в самом векторе:

let index = my_vec.iter().position(|&r| r == max_value).unwrap();

Чтобы получить этот результатвам нужно повторить дважды по одному и тому же вектору.Чтобы повысить производительность, вы можете вернуть значение индекса с максимальным значением в качестве кортежа в итерации fold.

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

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