1use crate::error::Error;
17
18#[derive(Debug, Clone)]
20pub enum Key<'a> {
21 Numeric(&'a [f64]),
23 Categorical(&'a [String]),
25}
26
27impl Key<'_> {
28 fn len(&self) -> usize {
29 match self {
30 Key::Numeric(v) => v.len(),
31 Key::Categorical(v) => v.len(),
32 }
33 }
34
35 fn ranks(&self) -> Result<Vec<f64>, Error> {
38 match self {
39 Key::Numeric(v) => {
40 if let Some(bad) = v.iter().find(|x| !x.is_finite()) {
41 return Err(Error::Input(format!(
42 "sort keys must be finite; found {bad}"
43 )));
44 }
45 Ok(v.to_vec())
46 }
47 Key::Categorical(v) => {
48 let mut levels: Vec<&str> = v.iter().map(String::as_str).collect();
49 levels.sort_unstable();
50 levels.dedup();
51 Ok(v.iter()
52 .map(|s| (levels.binary_search(&s.as_str()).unwrap() + 1) as f64)
53 .collect())
54 }
55 }
56 }
57}
58
59fn rank_columns(keys: &[Key]) -> Result<(Vec<Vec<f64>>, usize), Error> {
60 if keys.is_empty() {
61 return Err(Error::Input("at least one sort key is needed".into()));
62 }
63 let n = keys[0].len();
64 if n == 0 {
65 return Err(Error::Input("sort keys must not be empty".into()));
66 }
67 let mut ranks = Vec::with_capacity(keys.len());
68 for key in keys {
69 if key.len() != n {
70 return Err(Error::Input(format!(
71 "sort keys of different lengths: {} and {}",
72 n,
73 key.len()
74 )));
75 }
76 ranks.push(key.ranks()?);
77 }
78 Ok((ranks, n))
79}
80
81fn multi_key_order(ranks: &[Vec<f64>], n: usize) -> Vec<usize> {
83 let mut order: Vec<usize> = (0..n).collect();
84 order.sort_by(|&a, &b| {
85 for col in ranks {
86 match col[a].partial_cmp(&col[b]).unwrap() {
87 std::cmp::Ordering::Equal => continue,
88 other => return other,
89 }
90 }
91 std::cmp::Ordering::Equal
92 });
93 order
94}
95
96pub fn nested(keys: &[Key]) -> Result<Vec<usize>, Error> {
100 let (ranks, n) = rank_columns(keys)?;
101 Ok(multi_key_order(&ranks, n))
102}
103
104pub fn serpentine(keys: &[Key]) -> Result<Vec<usize>, Error> {
112 let (ranks, n) = rank_columns(keys)?;
113 if ranks.len() == 1 {
114 return Ok(multi_key_order(&ranks, n));
115 }
116
117 let mut order = multi_key_order(&ranks[..1], n);
118 for j in 1..ranks.len() {
119 let mut changes = vec![false; n];
122 changes[0] = true;
123 for col in &ranks[..j] {
124 for p in 1..n {
125 changes[p] = changes[p] || col[order[p]] != col[order[p - 1]];
126 }
127 }
128 let mut level = vec![0_i64; n];
129 let mut running = 0_i64;
130 for p in 0..n {
131 running += i64::from(changes[p]);
132 level[p] = running;
133 }
134
135 let mut positions: Vec<usize> = (0..n).collect();
136 positions.sort_by(|&a, &b| {
137 level[a].cmp(&level[b]).then_with(|| {
138 let direction = |p: usize| if level[p] % 2 == 1 { 1.0 } else { -1.0 };
139 let ka = direction(a) * ranks[j][order[a]];
140 let kb = direction(b) * ranks[j][order[b]];
141 ka.partial_cmp(&kb).unwrap()
142 })
143 });
144 order = positions.iter().map(|&p| order[p]).collect();
145 }
146 Ok(order)
147}