获取片中最大或最小浮点值的索引或Rust中的Vec的惯用方法是什么?

Jux*_*hin 4 algorithm floating-point idiomatic rust

假设 -该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
Run Code Online (Sandbox Code Playgroud)

获取上述列表中最高值索引的最新且最稳定的方法是什么(值可以是负数)?

我最初的尝试大致如下:

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

哪里nets&Vec<f32>.对我来说,这显然是不正确的.

相当于Python的Python(考虑到上面的假设):

_i = nets.index(max(nets))
Run Code Online (Sandbox Code Playgroud)

Sta*_*eur 6

我可能会做这样的事情:

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(())
}
Run Code Online (Sandbox Code Playgroud)

这可以通过在 Iterator 上添加一个 trait 来实现,例如 function try_max_by


Emi*_*ily 6

有什么理由为什么这行不通?

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);
}
Run Code Online (Sandbox Code Playgroud)

  • [*您不应该使用`partial_cmp(b).unwrap_or(Ordering::Equal)`,因为当存在 NaN 时它会提供不稳定的结果*](/sf/answers/3521585231/)。这个 OP 特别保证没有 NaN,但预计答案会警告不注意的人。 (2认同)
  • 我只会`expect("You promise no NaNs!")` 而不是`unwrap_or` 以符合OP 保证。此外,将切片作为参数而不是 Vec。 (2认同)

Web*_*rix 5

您可以通过以下方式找到最大值:

let mut max_value = my_vec.iter().fold(0.0f32, |max, &val| if val > max{ val } else{ max });
Run Code Online (Sandbox Code Playgroud)

找到后,max_value您可以跟踪它在矢量本身中的位置:

let index = my_vec.iter().position(|&r| r == max_value).unwrap();
Run Code Online (Sandbox Code Playgroud)

为了得到这个结果,你需要在同一个向量上迭代两次。为了提高性能,您可以在fold迭代中将具有最大值的索引值作为元组返回。

操场


Pet*_*all 5

这很棘手的原因是因为f32没有实现Ord.这是因为NaN值会阻止浮点数形成总订单,这违反了合同Ord.

通过定义一个不允许包含a的数字类型包装,可以解决这个问题NaN.一个例子是有序浮动.如果您使用此包来首先准备集合以包含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();
Run Code Online (Sandbox Code Playgroud)

将此添加到Cargo.toml:

[dependencies]
ordered-float = "1.0.1"
Run Code Online (Sandbox Code Playgroud)

额外材料:通过利用具有透明表示的事实,类型转换可以真正实现零成本(假设您确实没有NaN值!)NotNan

let non_nan_floats: Vec<NotNan<f32>> = unsafe { mem::transmute(nets) };
Run Code Online (Sandbox Code Playgroud)

  • @Juxhin请记住,Rust标准库的设计理念之一是慢慢采用新的API,而是鼓励在社区中出现功能.因此,你很难找到一个没有外部依赖关系的Rust项目,并且了解流行的板条箱确实是Rust生产效率的重要组成部分. (2认同)