What is the idiomatic way to get the index of a maximum or minimum floating point value in a slice or Vec in Rust?

前端 未结 5 2048
盖世英雄少女心
盖世英雄少女心 2021-01-18 03:09

Assumption -- The Vec does not have any NaN values or exhibit any NaN behavior.

T

5条回答
  •  说谎
    说谎 (楼主)
    2021-01-18 03:54

    The reason why this is tricky is because f32 does not implement Ord. That is because NaN values prevent floating point numbers from forming a total order, which violates the contract of Ord.

    There are 3rd party crates that work around this by defining a numeric type wrapper which is not allowed to contain a NaN. One example is ordered-float. If you use this crate to first prepare the collection to contain NotNan values, then you can write code very close to your original idea:

    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();
    

    Add this to Cargo.toml:

    [dependencies]
    ordered-float = "1.0.1"
    

    Bonus material: The type conversion can be made truly zero-cost (assuming you are really sure that there are no NaN values!), by taking advantage of the fact that NotNan has a transparent representation:

    let non_nan_floats: Vec> = unsafe { mem::transmute(nets) };
    

提交回复
热议问题