这是Day 1 of Advent of Code 2023的一部分。我想提取数字,获得第一个和最后一个字符,并转换回整数。这是工作版本。
fn main() {
let line = "treb7uchet";
// Find all the digit
let v: String = line
.chars()
// Filter the numeric character
.filter(|c| c.is_numeric() )
// Only filter the first element
// .enumerate()
// .filter(|&(i, _)| i == 0)
// .map(|(_, e)| e)
.collect::<String>();
// println!("{}", v);
// Get the first and the last digit, convert into number
let my_int: i32 = format!("{}{}", v.chars().nth(0).unwrap(), v.chars().last().unwrap())
.parse()
.unwrap();
println!("{}", my_int);
}
Ans: 77
字符串
这段代码已经可以工作了,但是我想知道我是否可以在1行代码而不是2行代码上运行所有内容。我尝试了enumerate
(注解代码),但是它只能filter
第一项(通过知道它的索引)。我想知道如何过滤最后一项。或者有什么方法可以提取迭代器中的最后一个和第一个元素?
先谢了。
请随意在Rust playground中测试它。
2条答案
按热度按时间hjzp0vay1#
有一个简单得多的零拷贝解决方案。
char::to_digit
返回一个Option
,如果字符是一个有效的数字,它将是Some
,数字将是u32
。我们可以利用filter_map
来生成一个字符串中的字符的迭代器,这些字符是数字,转换为u32
:字符串
因为
Chars
是一个DoubleEndedIterator
,所以我们可以从两端取。但是,由于字符串中的第一个和最后一个字符可以是同一个字符,所以我们不能只调用next
,然后再调用next_back
,因为当字符串包含个位数时,next_back
将返回None
。我们可以通过存储第一个数字来解决这个问题,然后在
next_back
返回None
的情况下将其用作默认值。型
为了生成一行的数字,我们只需将第一位数字乘以10,然后将其添加到最后一位数字:
型
请注意,在这段代码中,我们没有分配
String
然后解析它!我们只是在操作数字;没有堆分配。我们可以将此合并与多行迭代相结合,以产生非常快速且易于理解的解决方案:
型
IMO这比单行Map函数更具可读性。
现在,如果你 * 真的想要一行 *,即使它很难阅读,那么你可以实现这一点,尽管注意它重复了创建迭代器的代码:
型
这行代码足够长,rustfmt希望将其 Package 到多行代码中--甚至比我给予的先前方法还要多。
从技术上讲,您可以将任何程序编写为一行程序,但我们有一个很好的理由不这样做,所以我强烈建议您重新考虑您的一行程序解决方案的目标。
vdgimpew2#
由于任务只有短字符串和更少的数字,我们可以负担O(n)运行所有数字。
这里的技巧是使用一个迭代器方法来维护一个状态,并使用这个状态来保存第一个数字。初始状态由一个特定的值编码,并在单个数字的情况下触发加倍。
第一个想法保持了数字的
char
性质。字符串
第二个想法利用了
to_digit()
的优点,甚至更简单。型
最后一个简单的步骤来总结所有两位数的数字是作为一个练习,并不难。