1use itertools::Itertools;
33
34#[derive(Clone, Copy, PartialEq, Debug)]
35pub struct CharsCounter {
36 pub character: char,
37 pub count: usize,
38}
39
40pub trait ICharsCounter {
41 fn count_chars(&self) -> Vec<CharsCounter>;
42 fn count_chars_ascii(&self) -> Vec<CharsCounter>;
43 fn count_chars_numeric(&self) -> Vec<CharsCounter>;
44 fn count_chars_alphabetic(&self) -> Vec<CharsCounter>;
45 fn count_chars_alphanumeric(&self) -> Vec<CharsCounter>;
46 fn count_chars_whitespace(&self) -> Vec<CharsCounter>;
47 fn count_chars_no_whitespace(&self) -> Vec<CharsCounter>;
48 fn count_chars_chinese(&self) -> Vec<CharsCounter>;
49
50 fn count_chars_filter<P>(&self, predicate: P) -> Vec<CharsCounter>
51 where
52 P: FnMut(&char) -> bool;
53}
54
55pub trait ICharCounterExt {
56 fn most_chars(&self) -> Vec<CharsCounter>;
57 fn least_chars(&self) -> Vec<CharsCounter>;
58 fn find_by_num(&self, n: usize) -> Vec<CharsCounter>;
59 fn find_by_char(&self, c: char) -> Option<CharsCounter>;
60 fn counter_filter<P>(&self, predicate: P) -> Vec<CharsCounter>
61 where
62 P: FnMut(&&CharsCounter) -> bool;
63}
64
65impl ICharsCounter for &str {
66 fn count_chars(&self) -> Vec<CharsCounter> {
67 self.count_chars_filter(|_| true)
68 }
69
70 fn count_chars_ascii(&self) -> Vec<CharsCounter> {
71 self.count_chars_filter(|x| x.is_ascii())
72 }
73
74 fn count_chars_numeric(&self) -> Vec<CharsCounter> {
75 self.count_chars_filter(|x| x.is_numeric())
76 }
77
78 fn count_chars_alphabetic(&self) -> Vec<CharsCounter> {
79 self.count_chars_filter(|x| x.is_alphabetic())
80 }
81
82 fn count_chars_alphanumeric(&self) -> Vec<CharsCounter> {
83 self.count_chars_filter(|x| x.is_alphanumeric())
84 }
85
86 fn count_chars_whitespace(&self) -> Vec<CharsCounter> {
87 self.count_chars_filter(|x| x.is_whitespace())
88 }
89
90 fn count_chars_no_whitespace(&self) -> Vec<CharsCounter> {
91 self.count_chars_filter(|x| *x != ' ')
92 }
93
94 fn count_chars_chinese(&self) -> Vec<CharsCounter> {
95 self.count_chars_filter(|x| *x as u32 >= 19968 && *x as u32 <= 40959)
96 }
97
98 fn count_chars_filter<P>(&self, predicate: P) -> Vec<CharsCounter>
99 where
100 P: FnMut(&char) -> bool,
101 {
102 self.chars()
103 .filter(predicate)
104 .into_group_map_by(|&x| x)
105 .into_iter()
106 .map(|x| CharsCounter {
107 character: x.0,
108 count: x.1.len(),
109 })
110 .sorted_by(|x, y| y.count.cmp(&x.count).then(x.character.cmp(&y.character)))
111 .collect::<Vec<_>>()
112 }
113}
114
115impl ICharCounterExt for Vec<CharsCounter> {
116 fn most_chars(&self) -> Vec<CharsCounter> {
117 self.counter_filter(|x| x.count == self[0].count)
118 }
119
120 fn least_chars(&self) -> Vec<CharsCounter> {
121 self.counter_filter(|x| x.count == self[self.len() - 1].count)
122 }
123
124 fn find_by_num(&self, n: usize) -> Vec<CharsCounter> {
125 self.counter_filter(|x| x.count == n)
126 }
127
128 fn find_by_char(&self, c: char) -> Option<CharsCounter> {
129 self.iter().find(|x| x.character == c).map(|&x| x)
130 }
131
132 fn counter_filter<P>(&self, predicate: P) -> Vec<CharsCounter>
133 where
134 P: FnMut(&&CharsCounter) -> bool,
135 {
136 self.iter()
137 .filter(predicate)
138 .map(|&x| x)
139 .collect::<Vec<_>>()
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use crate::{CharsCounter, ICharCounterExt, ICharsCounter};
146
147 #[test]
148 fn most_chars_test() {
149 let str = "Hello world!";
150 let result = str.count_chars().most_chars();
151 assert_eq!(
152 result[0],
153 CharsCounter {
154 character: 'l',
155 count: 3
156 }
157 );
158 }
159
160 #[test]
161 fn least_chars_test() {
162 let str = "Hello world!";
163 let result = str.count_chars().least_chars();
164 assert_eq!(
165 result[0],
166 CharsCounter {
167 character: ' ',
168 count: 1
169 }
170 );
171 }
172
173 #[test]
174 fn find_by_num_test() {
175 let str = "Hello world!";
176 let result = str.count_chars().find_by_num(2);
177 assert_eq!(
178 result[0],
179 CharsCounter {
180 character: 'o',
181 count: 2
182 }
183 );
184 }
185
186 #[test]
187 fn find_by_char_test() {
188 let str = "Hello world!";
189 let result = str.count_chars().find_by_char('H').unwrap();
190 assert_eq!(
191 result,
192 CharsCounter {
193 character: 'H',
194 count: 1
195 }
196 );
197 }
198}