Find lines that appear exactly once in both sequences and match. Returns a list of matches sorted by position in the old sequence.
(old: &[Line<'a>], new: &[Line<'a>])
| 163 | /// |
| 164 | /// Returns a list of matches sorted by position in the old sequence. |
| 165 | fn find_unique_matches<'a>(old: &[Line<'a>], new: &[Line<'a>]) -> Vec<UniqueMatch> { |
| 166 | // Count occurrences in old sequence |
| 167 | let mut old_counts: HashMap<u64, (usize, usize)> = HashMap::new(); // hash -> (count, index) |
| 168 | for (idx, line) in old.iter().enumerate() { |
| 169 | let hash = line.hash_value(); |
| 170 | old_counts |
| 171 | .entry(hash) |
| 172 | .and_modify(|(count, _)| *count += 1) |
| 173 | .or_insert((1, idx)); |
| 174 | } |
| 175 | |
| 176 | // Count occurrences in new sequence and find matches |
| 177 | let mut new_counts: HashMap<u64, (usize, usize)> = HashMap::new(); |
| 178 | for (idx, line) in new.iter().enumerate() { |
| 179 | let hash = line.hash_value(); |
| 180 | new_counts |
| 181 | .entry(hash) |
| 182 | .and_modify(|(count, _)| *count += 1) |
| 183 | .or_insert((1, idx)); |
| 184 | } |
| 185 | |
| 186 | // Find lines that are unique in both and actually match |
| 187 | let mut matches = Vec::new(); |
| 188 | for (idx, line) in old.iter().enumerate() { |
| 189 | let hash = line.hash_value(); |
| 190 | |
| 191 | // Check if unique in old |
| 192 | if let Some(&(old_count, _)) = old_counts.get(&hash) { |
| 193 | if old_count != 1 { |
| 194 | continue; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | // Check if unique in new and find the index |
| 199 | if let Some(&(new_count, new_idx)) = new_counts.get(&hash) { |
| 200 | if new_count != 1 { |
| 201 | continue; |
| 202 | } |
| 203 | |
| 204 | // Verify actual equality (not just hash match) |
| 205 | if old[idx] == new[new_idx] { |
| 206 | matches.push(UniqueMatch { |
| 207 | old_idx: idx, |
| 208 | new_idx, |
| 209 | }); |
| 210 | } |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | // Sort by old_idx (should already be sorted, but ensure it) |
| 215 | matches.sort_by_key(|m| m.old_idx); |
| 216 | |
| 217 | matches |
| 218 | } |
| 219 | |
| 220 | /// Find the Longest Increasing Subsequence of matches by new_idx. |
| 221 | /// |