1pub fn fuzzy_sort<T: AsRef<str> + Clone>(to_sort: &[T], input: &str) -> Vec<T> {
2 let mut clone: Vec<T> = to_sort.to_vec();
3 let input_chars: Vec<char> = input.chars().collect();
4 clone.sort_by_key(|s| levenshtein_distance(s.as_ref(), &input_chars));
5
6 clone
7}
8
9pub fn fuzzy_sort_in_place<T: AsRef<str>>(to_sort: &mut [T], input: &str) {
10 let input_chars: Vec<char> = input.chars().collect();
11 to_sort.sort_by_key(|s| levenshtein_distance(s.as_ref(), &input_chars));
12}
13
14fn levenshtein_distance(u: &str, v_chars: &[char]) -> u32 {
15 let u_chars: Vec<char> = u.chars().collect();
16
17 let m = u_chars.len();
18 let n = v_chars.len();
19
20 let mut prev_row: Vec<u32> = (0..=n as u32).collect();
21 let mut current_row: Vec<u32> = vec![0; n + 1];
22
23 for i in 1..=m {
24 current_row[0] = i as u32;
25 for j in 1..=n {
26 let u_char = u_chars[i - 1];
27 let v_char = v_chars[j - 1];
28
29 let replacement_score = prev_row[j - 1] + (
30 if u_char == v_char { 0 } else { 1 }
31 );
32
33 let insert_score = current_row[j - 1] + 1;
34 let delete_score = prev_row[j] + 1;
35
36 current_row[j] = replacement_score
37 .min(insert_score)
38 .min(delete_score)
39 }
40
41 std::mem::swap(&mut prev_row, &mut current_row);
42 }
43
44 return prev_row[n];
45}
46
47#[test]
48fn fuzzy_sort_test() {
49 let test_cases = vec![
50 (
51 vec!["xxx".to_string(), "yyy".to_string(), "xx".to_string()],
52 "xxx",
53 vec!["xxx".to_string(), "xx".to_string(), "yyy".to_string()]
54 ),
55 (
56 vec!["apple".to_string(), "banana".to_string(), "cherry".to_string()],
57 "banana",
58 vec!["banana".to_string(), "apple".to_string(), "cherry".to_string()]
59 ),
60 (
61 vec!["rust".to_string(), "is".to_string(), "awesome".to_string()],
62 "awesome",
63 vec!["awesome".to_string(), "rust".to_string(), "is".to_string()]
64 ),
65 ];
66
67 test_cases.iter().for_each(|(arr, input, expected_sorted)| {
68 let sorted = fuzzy_sort(&arr, input);
69 assert_eq!(sorted, *expected_sorted);
70
71 let mut mutarr = arr.clone();
72 fuzzy_sort_in_place(mutarr.as_mut(), input);
73 assert_eq!(mutarr, *expected_sorted);
74 });
75}
76
77#[test]
78fn levenshtein_distance_test() {
79 vec![
80 ("hello, world", "hello- world", 1),
81 ("murice", "maurice", 1),
82 ("delete", "insert", 5),
83 ("Tier", "Tor", 2),
84 ("banana", "cherry", 6)
85 ].iter()
86 .for_each(|(u, v, expected_distance)| {
87 let distance = levenshtein_distance(u, &v.chars().collect::<Vec<_>>());
88 assert_eq!(distance, *expected_distance as u32);
89 });
90}