如何使用迭代器确定两个字符串是否只有一个不同的字符?
How to determine if two strings have only one different character in a functional style with iterators?
我需要编写一个函数来检查两个 String
是否以顺序方式恰好在一个字符上不同,即只有 diff("aba", "abc") == true
、diff("aab", "cab") == false
、字符串长度相等).
我写的代码是命令式的,但是看起来很难看,我想用迭代器写成函数式的。
我想它应该是带有 s1.chars()..enumerate()
+ 一些闭包的东西,它检测两个字符串中的一个不同字符。
fn has_one_difference(s1: &String, s2: &String) -> bool {
let mut diff_chars_limit = false;
let mut s1_chars = s1.chars();
let mut s2_chars = s2.chars();
for index in 0..s1.len() {
if s1_chars.nth(index).unwrap() != s2_chars.nth(index).unwrap() {
if diff_chars_limit {
return false
} else {
diff_chars_limit = true
}
}
}
return diff_chars_limit;
}
我收到此错误:
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:345:21
在字符串迭代的最后一个字符上。
首先,我将您的命令式代码更正为
- 删除字符迭代器中极其低效的基于索引的访问,
- 如果
s1
更长但在其他方面等于 s2
则移除崩溃并将其替换为相同的 "ignore tail of longer string" 您的代码表现出相反行为的行为,
- 使用
str
而不是 String
因为几乎没有充分的理由将 &String
传递给函数,并且
- 修复了一些小的样式问题;特别是在 return 中添加分号,但使用没有 return 的尾部 return 表达式。这是更惯用的 Rust。
看起来像这样:
fn has_one_difference(s1: &str, s2: &str) -> bool {
let mut found_one_difference = false;
for (c1, c2) in s1.chars().zip(s2.chars()) {
if c1 != c2 {
if found_one_difference {
return false;
} else {
found_one_difference = true
}
}
}
found_one_difference
}
现在对于功能版本,我会简单地编写一个迭代器,看看我是否可以对它调用 next()
两次:
fn has_one_difference_functional(s1: &str, s2: &str) -> bool {
// An iterator over different char pairs.
let mut iter = s1.chars().zip(s2.chars())
.filter(|(c1, c2)| c1 != c2);
// First call to next() must succeed (one difference), second must fail.
iter.next().is_some() && iter.next().is_none()
}
这不是完整的功能,但我认为它总体上是简洁性和可读性的最佳结合。一个简单的全功能版本将在组合迭代器上调用 count()
并将其与 1 进行比较,但这不是短路,因此效率低于需要。可以使用 try_fold
编写更高效的版本,但由于复杂性而失去可读性,因此我只会考虑将其用于 has_n_differences
函数。
我需要编写一个函数来检查两个 String
是否以顺序方式恰好在一个字符上不同,即只有 diff("aba", "abc") == true
、diff("aab", "cab") == false
、字符串长度相等).
我写的代码是命令式的,但是看起来很难看,我想用迭代器写成函数式的。
我想它应该是带有 s1.chars()..enumerate()
+ 一些闭包的东西,它检测两个字符串中的一个不同字符。
fn has_one_difference(s1: &String, s2: &String) -> bool {
let mut diff_chars_limit = false;
let mut s1_chars = s1.chars();
let mut s2_chars = s2.chars();
for index in 0..s1.len() {
if s1_chars.nth(index).unwrap() != s2_chars.nth(index).unwrap() {
if diff_chars_limit {
return false
} else {
diff_chars_limit = true
}
}
}
return diff_chars_limit;
}
我收到此错误:
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:345:21
在字符串迭代的最后一个字符上。
首先,我将您的命令式代码更正为
- 删除字符迭代器中极其低效的基于索引的访问,
- 如果
s1
更长但在其他方面等于s2
则移除崩溃并将其替换为相同的 "ignore tail of longer string" 您的代码表现出相反行为的行为, - 使用
str
而不是String
因为几乎没有充分的理由将&String
传递给函数,并且 - 修复了一些小的样式问题;特别是在 return 中添加分号,但使用没有 return 的尾部 return 表达式。这是更惯用的 Rust。
看起来像这样:
fn has_one_difference(s1: &str, s2: &str) -> bool {
let mut found_one_difference = false;
for (c1, c2) in s1.chars().zip(s2.chars()) {
if c1 != c2 {
if found_one_difference {
return false;
} else {
found_one_difference = true
}
}
}
found_one_difference
}
现在对于功能版本,我会简单地编写一个迭代器,看看我是否可以对它调用 next()
两次:
fn has_one_difference_functional(s1: &str, s2: &str) -> bool {
// An iterator over different char pairs.
let mut iter = s1.chars().zip(s2.chars())
.filter(|(c1, c2)| c1 != c2);
// First call to next() must succeed (one difference), second must fail.
iter.next().is_some() && iter.next().is_none()
}
这不是完整的功能,但我认为它总体上是简洁性和可读性的最佳结合。一个简单的全功能版本将在组合迭代器上调用 count()
并将其与 1 进行比较,但这不是短路,因此效率低于需要。可以使用 try_fold
编写更高效的版本,但由于复杂性而失去可读性,因此我只会考虑将其用于 has_n_differences
函数。