code never broke
never has ide reported "problems (43)"
This commit is contained in:
1 parent
de5d5cc62c
commit
af82016d1c
3 files changed
+261
-119
No files matched your search
Whitespace-only changes.
+260
-119
@@ -7,12 +7,120 @@
|
|||||||
/// position? idk
|
/// position? idk
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum EditOperation<T> {
|
pub enum EditOperation<T> {
|
||||||
Insert { elem: T }, // Insert a character from the target string
|
Insert { elem: T },
|
||||||
Delete { elem: T }, // Delete a character from the source string
|
Delete { elem: T },
|
||||||
Substitute { from: T, to: T }, // Replace one character with another
|
Substitute { from: T, to: T },
|
||||||
Match { elem: T }, // Characters match, no operation
|
Match { elem: T },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum MiniEditOperation {
|
||||||
|
Insert,
|
||||||
|
Delete,
|
||||||
|
Substitute,
|
||||||
|
Match,
|
||||||
|
}
|
||||||
|
|
||||||
|
// trait EditOperationCoords {
|
||||||
|
// fn coord_offset(self) -> (i32, i32);
|
||||||
|
// }
|
||||||
|
// // impl<T> EditOperationCoords for EditOperation<T> {
|
||||||
|
// // fn coord_offset(&self) -> (i32, i32) {
|
||||||
|
// // use EditOperation::*;
|
||||||
|
// // match self {
|
||||||
|
// // Delete { .. } => (-1, 0),
|
||||||
|
// // Insert { .. } => (0, -1),
|
||||||
|
// // Substitute { .. } | Match { .. } => (-1, -1),
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// impl<U> EditOperationCoords for U
|
||||||
|
// where
|
||||||
|
// MiniEditOperation: From<U>,
|
||||||
|
// {
|
||||||
|
// fn coord_offset(self) -> (i32, i32) {
|
||||||
|
// use MiniEditOperation::*;
|
||||||
|
// match MiniEditOperation::from(self) {
|
||||||
|
// Delete => (-1, 0),
|
||||||
|
// Insert => (0, -1),
|
||||||
|
// Substitute | Match => (-1, -1),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl<T> From<EditOperation<T>> for MiniEditOperation {
|
||||||
|
fn from(value: EditOperation<T>) -> Self {
|
||||||
|
match value {
|
||||||
|
EditOperation::Delete { .. } => Self::Delete,
|
||||||
|
EditOperation::Insert { .. } => Self::Insert,
|
||||||
|
EditOperation::Match { .. } => Self::Match,
|
||||||
|
EditOperation::Substitute { .. } => Self::Substitute,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<&EditOperation<T>> for MiniEditOperation {
|
||||||
|
fn from(value: &EditOperation<T>) -> Self {
|
||||||
|
match value {
|
||||||
|
EditOperation::Delete { .. } => Self::Delete,
|
||||||
|
EditOperation::Insert { .. } => Self::Insert,
|
||||||
|
EditOperation::Match { .. } => Self::Match,
|
||||||
|
EditOperation::Substitute { .. } => Self::Substitute,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trait ToEditOperation {
|
||||||
|
fn full<T>(
|
||||||
|
&self,
|
||||||
|
maybe_s1: Option<T>,
|
||||||
|
maybe_s2: Option<T>,
|
||||||
|
) -> Result<EditOperation<T>,()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToEditOperation for MiniEditOperation {
|
||||||
|
fn full<T>(
|
||||||
|
&self, // edit_operation
|
||||||
|
maybe_s1: Option<T>,
|
||||||
|
maybe_s2: Option<T>,
|
||||||
|
) -> Result<EditOperation<T>, ()> {
|
||||||
|
match self {
|
||||||
|
MiniEditOperation::Insert => {
|
||||||
|
if let Some(s2) = maybe_s2 {
|
||||||
|
Ok(EditOperation::Insert { elem: s2 })
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MiniEditOperation::Delete => {
|
||||||
|
if let Some(s1) = maybe_s1 {
|
||||||
|
Ok(EditOperation::Delete { elem: s1 })
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MiniEditOperation::Substitute => {
|
||||||
|
if let Some(s1) = maybe_s1 {
|
||||||
|
if let Some(s2) = maybe_s2 {
|
||||||
|
Ok(EditOperation::Substitute { from: s1, to: s2 })
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MiniEditOperation::Match => {
|
||||||
|
if let Some(s1) = maybe_s1 {
|
||||||
|
Ok(EditOperation::Match { elem: s1 })
|
||||||
|
} else if let Some(s2) = maybe_s2 {
|
||||||
|
Ok(EditOperation::Match { elem: s2 })
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pub struct EditCost {
|
pub struct EditCost {
|
||||||
pub insert: i32,
|
pub insert: i32,
|
||||||
pub delete: i32,
|
pub delete: i32,
|
||||||
@@ -38,13 +146,47 @@ impl EditCost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// custom cost for each [`EditOperation`]s operation
|
|
||||||
pub trait CustomCost<T> {
|
/// custom cost for operations
|
||||||
fn cost(&self, operation: &EditOperation<T>) -> i32;
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lda_strdist::levenshtein::general::{EditOperation, CustomCost};
|
||||||
|
/// struct MyCost {}
|
||||||
|
/// impl CustomCost<&EditOperation<char>> for MyCost{
|
||||||
|
/// fn cost(&self, operation: &EditOperation<char>) -> i32 {
|
||||||
|
/// use EditOperation::*;
|
||||||
|
/// match operation {
|
||||||
|
/// Substitute{from: a, to: b} =>{
|
||||||
|
/// if *a == 'b' && *b == 'n' {
|
||||||
|
/// println!("what he tryna pull");
|
||||||
|
/// -6
|
||||||
|
/// } else {1}
|
||||||
|
/// },
|
||||||
|
/// _ => 0 // do your own brih
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait CustomCost<U>
|
||||||
|
where
|
||||||
|
MiniEditOperation: From<U>,
|
||||||
|
{
|
||||||
|
fn cost(&self, operation: U) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> CustomCost<T> for EditCost {
|
impl CustomCost<MiniEditOperation> for EditCost {
|
||||||
fn cost(&self, operation: &EditOperation<T>) -> i32 {
|
fn cost(&self, operation: MiniEditOperation) -> i32 {
|
||||||
|
match operation {
|
||||||
|
MiniEditOperation::Insert => self.insert,
|
||||||
|
MiniEditOperation::Delete => self.delete,
|
||||||
|
MiniEditOperation::Substitute => self.substitute,
|
||||||
|
MiniEditOperation::Match => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CustomCost<EditOperation<T>> for EditCost {
|
||||||
|
fn cost(&self, operation: EditOperation<T>) -> i32 {
|
||||||
match operation {
|
match operation {
|
||||||
EditOperation::Insert { .. } => self.insert,
|
EditOperation::Insert { .. } => self.insert,
|
||||||
EditOperation::Delete { .. } => self.delete,
|
EditOperation::Delete { .. } => self.delete,
|
||||||
@@ -56,13 +198,18 @@ impl<T> CustomCost<T> for EditCost {
|
|||||||
|
|
||||||
/// cost of operation and the operation itself
|
/// cost of operation and the operation itself
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CostOperation<T> {
|
pub struct CostOperation<U>
|
||||||
|
where
|
||||||
|
MiniEditOperation: From<U>,
|
||||||
|
{
|
||||||
pub cost: i32,
|
pub cost: i32,
|
||||||
pub operation: EditOperation<T>,
|
pub operation: U,
|
||||||
}
|
}
|
||||||
// absolutely phenomenal naming
|
// absolutely phenomenal naming
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
|
// use super::CostOperation;
|
||||||
|
|
||||||
impl<T: Debug> Display for EditOperation<T> {
|
impl<T: Debug> Display for EditOperation<T> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -76,9 +223,9 @@ impl<T: Debug> Display for EditOperation<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Debug> Display for CostOperation<T> {
|
impl<T: Debug> Display for CostOperation<EditOperation<T>> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "Cost: {}, Operation: {:#?}", self.cost, self.operation)
|
write!(f, "Cost: {}, Operation: {}", self.cost, self.operation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// returns the distance + the dp table for who needs it
|
/// returns the distance + the dp table for who needs it
|
||||||
@@ -88,11 +235,12 @@ pub fn generalized_levenshtein<T, F>(
|
|||||||
seq1: &[T],
|
seq1: &[T],
|
||||||
seq2: &[T],
|
seq2: &[T],
|
||||||
cost_calc: &F,
|
cost_calc: &F,
|
||||||
) -> (i32, Vec<Vec<Option<CostOperation<T>>>>)
|
) -> (i32, Vec<Vec<Option<CostOperation<MiniEditOperation>>>>)
|
||||||
where
|
where
|
||||||
T: PartialEq + Clone + Debug,
|
T: PartialEq + Clone + Debug,
|
||||||
F: CustomCost<T>,
|
F: CustomCost<EditOperation<T>>,
|
||||||
{
|
{
|
||||||
|
use MiniEditOperation::*;
|
||||||
let len1 = seq1.len();
|
let len1 = seq1.len();
|
||||||
let len2 = seq2.len();
|
let len2 = seq2.len();
|
||||||
|
|
||||||
@@ -100,111 +248,115 @@ where
|
|||||||
|
|
||||||
// Fill the base cases
|
// Fill the base cases
|
||||||
for i in 1..=len1 {
|
for i in 1..=len1 {
|
||||||
dp[i][0] = if i > 0 {
|
dp[i][0] = Some(CostOperation {
|
||||||
Some(CostOperation {
|
cost: i as i32,
|
||||||
cost: i as i32,
|
operation: Delete,
|
||||||
operation: EditOperation::Delete {
|
});
|
||||||
elem: seq1[i - 1].clone(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for j in 0..=len2 {
|
for j in 1..=len2 {
|
||||||
dp[0][j] = if j > 0 {
|
dp[0][j] = Some(CostOperation {
|
||||||
Some(CostOperation {
|
cost: j as i32,
|
||||||
cost: j as i32,
|
operation: Insert,
|
||||||
operation: EditOperation::Insert {
|
});
|
||||||
elem: seq2[j - 1].clone(),
|
}
|
||||||
},
|
|
||||||
})
|
// Handle the case where either sequence is empty
|
||||||
} else {
|
if len1 == 0 || len2 == 0 {
|
||||||
None
|
return (dp[len1][len2].as_ref().unwrap().cost, dp);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the DP table
|
// Fill the DP table
|
||||||
for i in 1..=len1 {
|
for i in 1..=len1 {
|
||||||
for j in 1..=len2 {
|
for j in 1..=len2 {
|
||||||
let cost = seq1[i - 1] == seq2[j - 1];
|
let cost = seq1[i - 1] == seq2[j - 1];
|
||||||
let delete_op = EditOperation::Delete {
|
let delete_cost = dp[i - 1][j].as_ref().map(|s| {
|
||||||
elem: seq1[i - 1].clone(),
|
s.cost
|
||||||
};
|
+ cost_calc.cost(EditOperation::Delete {
|
||||||
let delete_cost = dp[i - 1][j]
|
elem: seq1[i - 1].clone(),
|
||||||
.as_ref()
|
})
|
||||||
.and_then(|s| Some(s.cost + cost_calc.cost(&delete_op)));
|
});
|
||||||
|
|
||||||
let insert_op = EditOperation::Insert {
|
let insert_cost = dp[i][j - 1].as_ref().map(|c| {
|
||||||
elem: seq2[j - 1].clone(),
|
c.cost
|
||||||
};
|
+ cost_calc.cost(EditOperation::Insert {
|
||||||
let insert_cost = dp[i][j - 1]
|
elem: seq2[j - 1].clone(),
|
||||||
.as_ref()
|
})
|
||||||
.and_then(|c| Some(c.cost + cost_calc.cost(&insert_op)));
|
});
|
||||||
let sub_op = if cost {
|
|
||||||
EditOperation::Match {
|
|
||||||
elem: seq1[i - 1].clone(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
EditOperation::Substitute {
|
|
||||||
from: seq1[i - 1].clone(),
|
|
||||||
to: seq2[j - 1].clone(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let substitute_cost = dp[i - 1][j - 1]
|
let sub_op = if cost { Match } else { Substitute };
|
||||||
.as_ref()
|
let substitute_cost = dp[i - 1][j - 1].as_ref().map(|c| {
|
||||||
.and_then(|c| Some(c.cost + cost_calc.cost(&sub_op)));
|
c.cost
|
||||||
|
+ cost_calc.cost(if cost {
|
||||||
|
EditOperation::Match {
|
||||||
|
elem: seq1[i - 1].clone(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EditOperation::Substitute {
|
||||||
|
from: seq1[i - 1].clone(),
|
||||||
|
to: seq2[j - 1].clone(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
dp[i][j] = [
|
dp[i][j] = [
|
||||||
(delete_cost, delete_op),
|
(delete_cost, Delete),
|
||||||
(insert_cost, insert_op),
|
(insert_cost, Insert),
|
||||||
(substitute_cost, sub_op),
|
(substitute_cost, sub_op),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(c, o)| c.and_then(|c| Some((c, o))))
|
.filter_map(|(c, o)| c.and_then(|c| Some((c, o))))
|
||||||
.min_by_key(|c| c.0)
|
.min_by_key(|c| c.0)
|
||||||
.and_then(|(c, o)| {
|
.map(|(c, o)| CostOperation {
|
||||||
Some(CostOperation {
|
cost: c,
|
||||||
cost: c,
|
operation: o,
|
||||||
operation: o,
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(dp[len1][len2].as_ref().unwrap().cost, dp)
|
(dp[len1][len2].as_ref().unwrap().cost, dp)
|
||||||
}
|
}
|
||||||
|
|
||||||
///extract the optimized edit sequence from the dp table
|
///extract the optimized edit sequence from the dp table
|
||||||
///
|
///
|
||||||
/// strs there just for the len() lmfao
|
/// strs there just for the len() lmfao
|
||||||
pub fn edit_sequence<T: Clone>(dp: &Vec<Vec<Option<CostOperation<T>>>>) -> Vec<EditOperation<T>> {
|
pub fn edit_sequence<T: Clone>(
|
||||||
|
seq1: &[T],
|
||||||
|
seq2: &[T],
|
||||||
|
dp: &[Vec<Option<CostOperation<MiniEditOperation>>>],
|
||||||
|
) -> Vec<EditOperation<T>> {
|
||||||
let mut i = dp.len() - 1;
|
let mut i = dp.len() - 1;
|
||||||
let mut j = dp[0].len() - 1;
|
let mut j = dp[0].len() - 1;
|
||||||
let mut funny = Vec::new();
|
let mut funny = Vec::new();
|
||||||
|
|
||||||
while let Some(op) = dp
|
while let Some(op) = dp
|
||||||
.get(i)
|
.get(i)
|
||||||
.and_then(|row| row.get(j))
|
.and_then(|row| row.get(j))
|
||||||
.and_then(|op| Some(op.as_ref().unwrap().operation.clone()))
|
.and_then(|op| op.as_ref())
|
||||||
{
|
{
|
||||||
match op {
|
match op.operation {
|
||||||
EditOperation::Insert { .. } => j -= 1,
|
MiniEditOperation::Insert => j -= 1,
|
||||||
EditOperation::Delete { .. } => i -= 1,
|
MiniEditOperation::Delete => i -= 1,
|
||||||
EditOperation::Substitute { .. } | EditOperation::Match { .. } => {
|
MiniEditOperation::Substitute | MiniEditOperation::Match => {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
j -= 1;
|
j -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
funny.push(op);
|
funny.push(
|
||||||
|
MiniEditOperation::full(
|
||||||
|
&op.operation,
|
||||||
|
seq1.get(i).cloned(),
|
||||||
|
seq2.get(j).cloned(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
funny.reverse();
|
funny.reverse();
|
||||||
funny
|
funny
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_alignment<T: Clone + Debug>(
|
pub fn generate_alignment<T: Clone + Debug>(
|
||||||
operations: &Vec<Vec<Option<CostOperation<T>>>>,
|
operations: &[Vec<Option<CostOperation<EditOperation<T>>>>],
|
||||||
) -> (Vec<T>, Vec<T>) {
|
) -> (Vec<T>, Vec<T>) {
|
||||||
let mut aligned_seq1 = Vec::new();
|
let mut aligned_seq1 = Vec::new();
|
||||||
let mut aligned_seq2 = Vec::new();
|
let mut aligned_seq2 = Vec::new();
|
||||||
@@ -213,22 +365,22 @@ pub fn generate_alignment<T: Clone + Debug>(
|
|||||||
let mut j = operations[0].len() - 1;
|
let mut j = operations[0].len() - 1;
|
||||||
|
|
||||||
while let Some(op) = &operations[i][j] {
|
while let Some(op) = &operations[i][j] {
|
||||||
match op.operation {
|
match &op.operation {
|
||||||
EditOperation::Insert { ref elem } => {
|
EditOperation::Insert { elem } => {
|
||||||
aligned_seq2.push(elem.clone());
|
aligned_seq2.push(elem.clone());
|
||||||
j -= 1;
|
j -= 1;
|
||||||
}
|
}
|
||||||
EditOperation::Delete { ref elem } => {
|
EditOperation::Delete { elem } => {
|
||||||
aligned_seq1.push(elem.clone());
|
aligned_seq1.push(elem.clone());
|
||||||
i -= 1;
|
i -= 1;
|
||||||
}
|
}
|
||||||
EditOperation::Substitute { ref from, ref to } => {
|
EditOperation::Substitute { from, to } => {
|
||||||
aligned_seq1.push(from.clone());
|
aligned_seq1.push(from.clone());
|
||||||
aligned_seq2.push(to.clone());
|
aligned_seq2.push(to.clone());
|
||||||
i -= 1;
|
i -= 1;
|
||||||
j -= 1;
|
j -= 1;
|
||||||
}
|
}
|
||||||
EditOperation::Match { ref elem } => {
|
EditOperation::Match { elem } => {
|
||||||
aligned_seq1.push(elem.clone());
|
aligned_seq1.push(elem.clone());
|
||||||
aligned_seq2.push(elem.clone());
|
aligned_seq2.push(elem.clone());
|
||||||
i -= 1;
|
i -= 1;
|
||||||
@@ -250,47 +402,36 @@ pub fn generate_alignment<T: Clone + Debug>(
|
|||||||
pub fn levenstein_distance<T: PartialEq + Clone + Debug>(
|
pub fn levenstein_distance<T: PartialEq + Clone + Debug>(
|
||||||
seq1: &[T],
|
seq1: &[T],
|
||||||
seq2: &[T],
|
seq2: &[T],
|
||||||
cost: &impl CustomCost<T>,
|
cost: &impl CustomCost<EditOperation<T>>,
|
||||||
) -> (i32, Vec<EditOperation<T>>) {
|
) -> (i32, Vec<EditOperation<T>>)
|
||||||
|
where
|
||||||
|
MiniEditOperation: From<EditOperation<T>>,
|
||||||
|
{
|
||||||
let (c, d) = generalized_levenshtein(seq1, seq2, cost);
|
let (c, d) = generalized_levenshtein(seq1, seq2, cost);
|
||||||
(c, edit_sequence(&d))
|
(c, edit_sequence(seq1, seq2, &d))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get source str from [`edit_sequence`]
|
/// get source str from [`edit_sequence`]
|
||||||
pub fn reconstruct_from<T: Clone>(vector: &Vec<EditOperation<T>>) -> Vec<T> {
|
pub fn reconstruct_from<T: Clone>(vector: &[EditOperation<T>]) -> Vec<T> {
|
||||||
let mut result = Vec::new();
|
vector
|
||||||
for operation in vector {
|
.iter()
|
||||||
match operation {
|
.filter_map(|operation| match operation {
|
||||||
EditOperation::Insert { .. } => {}
|
EditOperation::Delete { elem } => Some(elem.clone()),
|
||||||
EditOperation::Delete { elem } => {
|
EditOperation::Substitute { from, .. } => Some(from.clone()),
|
||||||
result.push(elem.clone());
|
EditOperation::Match { elem } => Some(elem.clone()),
|
||||||
}
|
_ => None,
|
||||||
EditOperation::Substitute { from, .. } => {
|
})
|
||||||
result.push(from.clone());
|
.collect()
|
||||||
}
|
|
||||||
EditOperation::Match { elem } => {
|
|
||||||
result.push(elem.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
/// get changed str from [`edit_sequence`]
|
/// get changed str from [`edit_sequence`]
|
||||||
pub fn reconstruct_to<T: Clone>(vector: &Vec<EditOperation<T>>) -> Vec<T> {
|
pub fn reconstruct_to<T: Clone>(vector: &[EditOperation<T>]) -> Vec<T> {
|
||||||
let mut result = Vec::new();
|
vector
|
||||||
for operation in vector {
|
.iter()
|
||||||
match operation {
|
.filter_map(|operation| match operation {
|
||||||
EditOperation::Insert { elem } => {
|
EditOperation::Insert { elem } => Some(elem.clone()),
|
||||||
result.push(elem.clone());
|
EditOperation::Substitute { to, .. } => Some(to.clone()),
|
||||||
}
|
EditOperation::Match { elem } => Some(elem.clone()),
|
||||||
EditOperation::Delete { .. } => {}
|
_ => None,
|
||||||
EditOperation::Substitute { to, .. } => {
|
})
|
||||||
result.push(to.clone());
|
.collect()
|
||||||
}
|
|
||||||
EditOperation::Match { elem } => {
|
|
||||||
result.push(elem.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
pub mod levenshtein;
|
pub mod levenshtein;
|
||||||
|
pub mod common_subsequence;
|
||||||
pub mod wrapper_;
|
pub mod wrapper_;
|
||||||
Reference in new issue
Block a user