【问题标题】:String recursion in RustRust 中的字符串递归
【发布时间】:2023-01-11 03:18:36
【问题描述】:

在 Rust 中,我试图获得 a-z 字符的所有可能组合,直到固定长度且没有重复字母。

例如,对于一组有限的 a-f 和 3 的长度,我应该得到:

美国广播公司 abd 阿部 ABF 交流电 酸性 高手 活性碳纤维 亚行 ... ETC

我一直在努力通过递归来做到这一点,并且一直在努力解决所有权和借用问题。我设法做到这一点的唯一方法如下,但这是在各处克隆字符串并且效率非常低。标准库中可能有用于此的标准排列/组合函数,我不知道,但我有兴趣了解如何手动完成此操作。

fn main() {
    run(&String::new());
}

fn run(target: &String) {
    for a in 97..123 { // ASCII a..z
        if !target.contains(char::from(a)) {
            let next = target.clone() + char::from(a).to_string().as_str(); // Working but terrible
            if next.len() == 3 { // Required string size
                println!("{}", next);
            } else {
                run(&next);
            }
        }
    }
}

任何帮助将非常感激。

【问题讨论】:

  • “在那个返回整数的字符串上调用另一个函数”- 细节?
  • 有点太长无法详细解释,但它只是一个函数,它引用一个字符串并返回一个基于字符串内容的i32i32 可能因字符串而异,我想找到它的最大值。
  • 让我们移动“调用另一个函数”另一个问题的一部分。在 StackOverflow 上,每个帖子问一个问题是一种习惯。
  • 好的,编辑以删除问题的第二部分。

标签: string recursion rust


【解决方案1】:

首先,有几点说明:

  • &String 是一种很少见的反模式。它没有任何用处; String 超过 str 的所有功能都需要可变性。所以它应该是&mut String&str
  • 97..123 不常见......使用'a'..='z'

现在到实际问题:

只要将不可变字符串传递给递归,就无法绕过克隆数据。我会让字符串可变,然后您可以简单地从中添加和删除单个字符。

像这样:

fn main() {
    run(&mut String::new());
}

fn run(target: &mut String) {
    for a in 'a'..='z' {
        if !target.contains(a) {
            target.push(a);
            if target.len() == 3 {
                // Required string size
                println!("{}", target);
            } else {
                run(target);
            }
            target.pop();
        }
    }
}

【讨论】:

  • 谢谢你。我以前尝试过这种方法,但将 target.pop() 放在了错误的位置 :) 也感谢您提供的有用评论。当将 target 传递给另一个函数时,我是否应该发布另一个关于处理返回的问题,并提供指向这篇文章的链接?
  • 只需打开一个新问题,其中包含问题描述、您尝试过的内容以及您为何苦苦挣扎。
  • 没必要,我将你关于使用 &mut String 的建议应用到 &mut i32 上,我在递归中传递了它,发现最大值是显而易见的。非常感谢您的帮助。
【解决方案2】:

这是使用 itertools 的另一种方法。

直接从函数返回 String 对象可能更简洁。

use std::ops::RangeInclusive;
use itertools::Itertools;

fn main() {
    println!("result: {}",combine('a'..='d', 3));
    println!("result: {}",combine('a'..='g', 4));
    println!("result: {}",combine('a'..='c', 3));
    println!("result: {}",combine('a'..='c', 4)); // assertion fail
}

fn combine(range: RangeInclusive<char>, depth: usize) -> String
{
    assert!( *range.end() as usize - *range.start() as usize + 1 >= depth);

    let perms = range.permutations(depth);
    let mut result = String::new();

    perms.for_each(|mut item| {
        item.push(' ');
        result += &item.into_iter().collect::<String>();
    });
    result.pop(); // pop last superfluous space char
    result
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-06
    • 2017-10-28
    • 2015-06-25
    • 2014-02-19
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多