1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum RankMethod {
9 Average,
12 Min,
14 Max,
16 Ordinal,
18 Dense,
20}
21
22pub fn rank(data: &[f64], method: RankMethod) -> Vec<f64> {
29 let n = data.len();
30 if n == 0 {
31 return Vec::new();
32 }
33
34 let mut indexed: Vec<(f64, usize)> = data.iter().copied().enumerate().map(|(i, v)| (v, i)).collect();
36 indexed.sort_by(|a, b| a.0.total_cmp(&b.0));
37
38 let mut ranks = vec![0.0; n];
39
40 if method == RankMethod::Ordinal {
41 for (rank_minus_1, &(_, orig_idx)) in indexed.iter().enumerate() {
42 ranks[orig_idx] = (rank_minus_1 + 1) as f64;
43 }
44 } else {
45 let mut dense_rank = 0.0;
46 let mut i = 0;
47 while i < n {
48 let mut j = i + 1;
50 while j < n && indexed[j].0.total_cmp(&indexed[i].0).is_eq() {
51 j += 1;
52 }
53 dense_rank += 1.0;
54
55 let group_len = j - i;
57 let rank_val = match method {
58 RankMethod::Average => {
59 let sum: f64 = (i + 1..=j).map(|r| r as f64).sum();
60 sum / group_len as f64
61 }
62 RankMethod::Min => (i + 1) as f64,
63 RankMethod::Max => j as f64,
64 RankMethod::Dense => dense_rank,
65 RankMethod::Ordinal => unreachable!(),
66 };
67
68 for k in i..j {
69 ranks[indexed[k].1] = rank_val;
70 }
71
72 i = j;
73 }
74 }
75
76 ranks
77}
78
79#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn rank_average_no_ties() {
87 let data = [3.0, 1.0, 2.0];
88 assert_eq!(rank(&data, RankMethod::Average), vec![3.0, 1.0, 2.0]);
89 }
90
91 #[test]
92 fn rank_average_with_ties() {
93 let data = [3.0, 1.0, 2.0, 2.0];
94 assert_eq!(rank(&data, RankMethod::Average), vec![4.0, 1.0, 2.5, 2.5]);
96 }
97
98 #[test]
99 fn rank_min_with_ties() {
100 let data = [3.0, 1.0, 2.0, 2.0];
101 assert_eq!(rank(&data, RankMethod::Min), vec![4.0, 1.0, 2.0, 2.0]);
102 }
103
104 #[test]
105 fn rank_max_with_ties() {
106 let data = [3.0, 1.0, 2.0, 2.0];
107 assert_eq!(rank(&data, RankMethod::Max), vec![4.0, 1.0, 3.0, 3.0]);
108 }
109
110 #[test]
111 fn rank_dense_with_ties() {
112 let data = [3.0, 1.0, 2.0, 2.0];
113 assert_eq!(rank(&data, RankMethod::Dense), vec![3.0, 1.0, 2.0, 2.0]);
114 }
115
116 #[test]
117 fn rank_ordinal() {
118 let data = [3.0, 1.0, 2.0, 2.0];
119 let r = rank(&data, RankMethod::Ordinal);
121 assert_eq!(r[1], 1.0); assert_eq!(r[0], 4.0); assert!(r[2] == 2.0 || r[2] == 3.0);
125 assert!(r[3] == 2.0 || r[3] == 3.0);
126 assert!((r[2] - r[3]).abs() > 0.5); }
128
129 #[test]
130 fn rank_all_equal() {
131 let data = [5.0, 5.0, 5.0];
132 assert_eq!(rank(&data, RankMethod::Average), vec![2.0, 2.0, 2.0]);
133 assert_eq!(rank(&data, RankMethod::Dense), vec![1.0, 1.0, 1.0]);
134 }
135
136 #[test]
137 fn rank_empty() {
138 let empty: Vec<f64> = vec![];
139 assert_eq!(rank(&empty, RankMethod::Average), Vec::<f64>::new());
140 }
141}