Skip to content

Commit f9f6eb1

Browse files
committed
cleanup using iterator magic
1 parent dafd95b commit f9f6eb1

File tree

2 files changed

+53
-60
lines changed

2 files changed

+53
-60
lines changed

src/misc.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ impl PiecewiseLinearFn {
7070

7171
fn update_envelope(&mut self) {
7272
self.recent_lines.extend(self.sorted_lines.drain(..));
73-
self.recent_lines.sort_unstable_by(asserting_cmp);
73+
self.recent_lines.sort_unstable_by(asserting_cmp); // TODO: switch to O(n) merge
7474
self.intersections.clear();
7575

7676
for (new_m, new_b) in self.recent_lines.drain(..).rev() {
7777
while let Some(&(last_m, last_b)) = self.sorted_lines.last() {
7878
// If slopes are equal, get rid of the old line as its intercept is higher
7979
if (new_m - last_m).abs() > 1e-9 {
8080
let intr = (new_b - last_b) / (last_m - new_m);
81-
if self.intersections.last().map(|&x| x < intr).unwrap_or(true) {
81+
if self.intersections.last() < Some(&intr) {
8282
self.intersections.push(intr);
8383
break;
8484
}
@@ -92,9 +92,9 @@ impl PiecewiseLinearFn {
9292

9393
fn eval_helper(&self, x: f64) -> f64 {
9494
let idx = slice_lower_bound(&self.intersections, &x);
95-
std::iter::once(self.sorted_lines.get(idx))
96-
.flatten()
97-
.chain(self.recent_lines.iter())
95+
self.recent_lines
96+
.iter()
97+
.chain(self.sorted_lines.get(idx))
9898
.map(|&(m, b)| m * x + b)
9999
.min_by(asserting_cmp)
100100
.unwrap_or(1e18)

src/string_proc.rs

Lines changed: 48 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,12 @@ impl<'a, C: Eq> Matcher<'a, C> {
6161
///
6262
/// ```
6363
/// use contest_algorithms::string_proc::Matcher;
64-
/// let utf8_string = "hello";
65-
///
66-
/// let match_from_byte_literal = Matcher::new(b"hello");
67-
///
68-
/// let match_from_bytes = Matcher::new(utf8_string.as_bytes());
69-
///
64+
/// let byte_string: &[u8] = b"hello";
65+
/// let utf8_string: &str = "hello";
7066
/// let vec_char: Vec<char> = utf8_string.chars().collect();
67+
///
68+
/// let match_from_byte_literal = Matcher::new(byte_string);
69+
/// let match_from_utf8 = Matcher::new(utf8_string.as_bytes());
7170
/// let match_from_chars = Matcher::new(&vec_char);
7271
///
7372
/// let vec_int = vec![4, -3, 1];
@@ -93,24 +92,24 @@ impl<'a, C: Eq> Matcher<'a, C> {
9392
Self { pattern, fail }
9493
}
9594

96-
/// KMP algorithm, sets match_lens[i] = length of longest prefix of pattern
95+
/// KMP algorithm, sets @return[i] = length of longest prefix of pattern
9796
/// matching a suffix of text[0..=i].
98-
pub fn kmp_match(&self, text: &[C]) -> Vec<usize> {
99-
let mut match_lens = Vec::with_capacity(text.len());
97+
pub fn kmp_match(&self, text: impl IntoIterator<Item = C>) -> Vec<usize> {
10098
let mut len = 0;
101-
for ch in text {
102-
if len == self.pattern.len() {
103-
len = self.fail[len - 1];
104-
}
105-
while len > 0 && self.pattern[len] != *ch {
106-
len = self.fail[len - 1];
107-
}
108-
if self.pattern[len] == *ch {
109-
len += 1;
110-
}
111-
match_lens.push(len);
112-
}
113-
match_lens
99+
text.into_iter()
100+
.map(|ch| {
101+
if len == self.pattern.len() {
102+
len = self.fail[len - 1];
103+
}
104+
while len > 0 && self.pattern[len] != ch {
105+
len = self.fail[len - 1];
106+
}
107+
if self.pattern[len] == ch {
108+
len += 1;
109+
}
110+
len
111+
})
112+
.collect()
114113
}
115114
}
116115

@@ -141,7 +140,7 @@ impl<C: std::hash::Hash + Eq> MultiMatcher<C> {
141140

142141
/// Precomputes the automaton that allows linear-time string matching.
143142
/// If there are duplicate patterns, all but one copy will be ignored.
144-
pub fn new(patterns: Vec<impl IntoIterator<Item = C>>) -> Self {
143+
pub fn new(patterns: impl IntoIterator<Item = impl IntoIterator<Item = C>>) -> Self {
145144
let mut trie = Trie::default();
146145
let pat_nodes: Vec<usize> = patterns.into_iter().map(|pat| trie.insert(pat)).collect();
147146

@@ -171,16 +170,16 @@ impl<C: std::hash::Hash + Eq> MultiMatcher<C> {
171170
}
172171
}
173172

174-
/// Aho-Corasick algorithm, sets match_nodes[i] = node corresponding to
173+
/// Aho-Corasick algorithm, sets @return[i] = node corresponding to
175174
/// longest prefix of some pattern matching a suffix of text[0..=i].
176-
pub fn ac_match(&self, text: &[C]) -> Vec<usize> {
177-
let mut match_nodes = Vec::with_capacity(text.len());
175+
pub fn ac_match(&self, text: impl IntoIterator<Item = C>) -> Vec<usize> {
178176
let mut node = 0;
179-
for ch in text {
180-
node = Self::next(&self.trie, &self.fail, node, &ch);
181-
match_nodes.push(node);
182-
}
183-
match_nodes
177+
text.into_iter()
178+
.map(|ch| {
179+
node = Self::next(&self.trie, &self.fail, node, &ch);
180+
node
181+
})
182+
.collect()
184183
}
185184

186185
/// For each non-empty match, returns where in the text it ends, and the index
@@ -235,9 +234,9 @@ impl SuffixArray {
235234
}
236235

237236
/// Suffix array construction in O(n log n) time.
238-
pub fn new(text: &[u8]) -> Self {
239-
let n = text.len();
240-
let init_rank = text.iter().map(|&ch| ch as usize).collect::<Vec<_>>();
237+
pub fn new(text: impl IntoIterator<Item = u8>) -> Self {
238+
let init_rank = text.into_iter().map(|ch| ch as usize).collect::<Vec<_>>();
239+
let n = init_rank.len();
241240
let mut sfx = Self::counting_sort(0..n, &init_rank, 256);
242241
let mut rank = vec![init_rank];
243242
// Invariant at the start of every loop iteration:
@@ -291,7 +290,7 @@ impl SuffixArray {
291290
/// # Panics
292291
///
293292
/// Panics if text is empty.
294-
pub fn palindromes<T: Eq>(text: &[T]) -> Vec<usize> {
293+
pub fn palindromes(text: &[impl Eq]) -> Vec<usize> {
295294
let mut pal = Vec::with_capacity(2 * text.len() - 1);
296295
pal.push(1);
297296
while pal.len() < pal.capacity() {
@@ -339,27 +338,21 @@ mod test {
339338

340339
#[test]
341340
fn test_kmp_matching() {
342-
let text = b"banana";
343-
let pattern = b"ana";
341+
let pattern = "ana";
342+
let text = "banana";
344343

345-
let matches = Matcher::new(pattern).kmp_match(text);
344+
let matches = Matcher::new(pattern.as_bytes()).kmp_match(text.bytes());
346345

347346
assert_eq!(matches, vec![0, 1, 2, 3, 2, 3]);
348347
}
349348

350349
#[test]
351350
fn test_ac_matching() {
352-
let text = b"banana bans, apple benefits.";
353-
let dict = vec![
354-
"banana".bytes(),
355-
"benefit".bytes(),
356-
"banapple".bytes(),
357-
"ban".bytes(),
358-
"fit".bytes(),
359-
];
360-
361-
let matcher = MultiMatcher::new(dict);
362-
let match_nodes = matcher.ac_match(text);
351+
let dict = vec!["banana", "benefit", "banapple", "ban", "fit"];
352+
let text = "banana bans, apple benefits.";
353+
354+
let matcher = MultiMatcher::new(dict.iter().map(|s| s.bytes()));
355+
let match_nodes = matcher.ac_match(text.bytes());
363356
let end_pos_and_id = matcher.get_end_pos_and_pat_id(&match_nodes);
364357

365358
assert_eq!(
@@ -370,11 +363,11 @@ mod test {
370363

371364
#[test]
372365
fn test_suffix_array() {
373-
let text1 = b"bobocel";
374-
let text2 = b"banana";
366+
let text1 = "bobocel";
367+
let text2 = "banana";
375368

376-
let sfx1 = SuffixArray::new(text1);
377-
let sfx2 = SuffixArray::new(text2);
369+
let sfx1 = SuffixArray::new(text1.bytes());
370+
let sfx2 = SuffixArray::new(text2.bytes());
378371

379372
assert_eq!(sfx1.sfx, vec![0, 2, 4, 5, 6, 1, 3]);
380373
assert_eq!(sfx2.sfx, vec![5, 3, 1, 0, 4, 2]);
@@ -393,9 +386,9 @@ mod test {
393386

394387
#[test]
395388
fn test_palindrome() {
396-
let text = b"banana";
389+
let text = "banana";
397390

398-
let pal_len = palindromes(text);
391+
let pal_len = palindromes(text.as_bytes());
399392

400393
assert_eq!(pal_len, vec![1, 0, 1, 0, 3, 0, 5, 0, 3, 0, 1]);
401394
}

0 commit comments

Comments
 (0)