【问题标题】:How to determine if two strings have only one different character in a functional style with iterators?如何使用迭代器确定两个字符串在功能样式中是否只有一个不同的字符?
【发布时间】:2019-04-01 05:52:56
【问题描述】:

我需要编写一个函数来检查两个Strings 是否在一个字符上按顺序不同,即只有diff("aba", "abc") == truediff("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

在字符串迭代的最后一个字符上。

【问题讨论】:

  • 在我看来你忘了从字符串的长度中减去 1:(s1.len() - 1)Playground
  • 我不明白为什么你的一个例子是错误的。它们都在一个字符上不同,并且都一样长。你能再解释一下吗?
  • @AkinerAlkan 0..x 包含 0 和排除 x,问题是 s1_chars.nth mut 迭代器

标签: string rust char iterable


【解决方案1】:

首先,我将您的命令式代码更正为

  • 删除对字符迭代器的基于索引的极其低效的访问,
  • 如果s1 更长但等于s2,则删除崩溃,并将其替换为与您的代码相反的“忽略较长字符串的尾部”行为,
  • 使用str 而不是String,因为几乎没有充分的理由将&String 传递给函数,并且
  • 修复了一些小的样式问题;特别是在返回中添加分号,但使用不带返回的尾返回表达式。这是更惯用的 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 函数。

【讨论】:

  • s1.chars() .zip(s2.chars()) .filter(|(c1, c2)| c1 != c2) .nth(1) .is_none()
  • @Stargateur 不错,但它不区分“没有差异”和“一个差异”。
  • 但这超出了函数的范围吗?
  • @Stargateur 不像最初写的那样,不。
  • 不是短路的——使用take?:s1.chars().zip(s2.chars()).filter(|(c1, c2)| c1 != c2).take(2).count() == 1
猜你喜欢
  • 2018-03-03
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多