如何确定两个字符串在迭代器的函数式样式中是否只有一个不同的字符?

问题描述 投票:1回答:1

我需要编写一个函数来检查两个Strings是否按顺序方式在一个字符中有所不同,即只有diff("aba", "abc") == truediff("aab", "cab") == false,字符串长度相等)。

我用命令式的方式编写了代码,但它看起来很难看,我想用iterator用函数式编写它。

我想它应该是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

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

string rust char iterable
1个回答
3
投票

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

  • 删除对字符迭代器的非常低效的基于索引的访问,
  • 如果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函数。

© www.soinside.com 2019 - 2024. All rights reserved.