bitbelay_statistics/
lib.rs

1//! Statistical tests used within `bitbelay`.
2//!
3//! # Types of Tests
4//!
5//! * Tests related to the [Chi-squared distribution] are located in the
6//!   `chi_squared` module ([link](chi_squared)).
7//! * Tests related to the correlation, such as [Pearson] and [Spearman]
8//!   correlation, are located in the `correlation` module
9//!   ([link](correlation)).
10//!
11//! [Chi-squared distribution]: https://en.wikipedia.org/wiki/Chi-squared_distribution
12//! [Pearson]: https://en.wikipedia.org/wiki/Pearson_correlation_coefficient
13//! [Spearman]: https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient
14
15use std::collections::BTreeMap;
16
17pub mod chi_squared;
18pub mod correlation;
19
20/// Ranks the inputs according to their [sort order](std::cmp::Ord`).
21fn rank<T: Clone + Ord>(data: &[T]) -> Vec<usize> {
22    let mut sorted = data.to_vec();
23    sorted.sort();
24
25    let mut ranks = BTreeMap::new();
26    let mut current_rank = 1usize;
27
28    for value in sorted {
29        ranks.entry(value.clone()).or_insert_with(|| {
30            let rank = current_rank;
31            current_rank += 1;
32            rank
33        });
34    }
35
36    // SAFETY: we just went through every value in `data` above, so we know every
37    // element now exists and will be retrieved within `ranks`. Thus, this will
38    // always unwrap.
39    data.iter()
40        .map(|v| *ranks.get(v).unwrap())
41        .collect::<Vec<_>>()
42}
43
44#[cfg(test)]
45mod tests {
46    use crate::rank;
47
48    #[test]
49    fn rank_works_correctly() {
50        let input = &[1, 3, 5, 2, 4, 6];
51        assert_eq!(rank(input), input);
52
53        let input = &[20, 10, 40, 30];
54        assert_eq!(rank(input), &[2, 1, 4, 3]);
55    }
56}