将 ASCII 数字规范化为数字
Normalise ASCII numbers to digit numbers
Running example on play.rust-lang.org
fn main() {
show({
let number = b"123456";
for sequence in number.windows(6) {
let product = sequence.iter().fold(1, |a, &b| a * (b as u64));
println!("product of {:?} is {}", sequence, product);
}
});
}
我不需要像“[49, 50, 51, 52, 53, 54] 的乘积是 15312500000” 这样的输出,我需要括号中的正常数字和乘积的标准化结果。
尝试使用 - b'0'
减去 48 以获得第 5 行中的正常数字不起作用,即
a * ((b as u64) -b'0')
或
(a - b'0') * (b as u64)
似乎我在这里遗漏了一些东西,例如我不知道 fold() 中的 'a' 和 'b' 值到底是什么。谁能启发我? :)
查看the signature of fold
,我们可以看到它有两个参数:
fn fold<B, F>(self, init: B, f: F) -> B
where F: FnMut(B, Self::Item) -> B
init
,它是某种任意类型 B
,和 f
,它是一个闭包,它接受一个 B
值和一个来自迭代器的元素,为了计算一个新的 B
值。整个函数returns一个B
。这些类型强烈暗示发生了什么:闭包 f
在迭代器的连续元素上重复调用,将计算的 B
值传递给下一个 f
调用。检查 the implementation 证实了这个怀疑:
let mut accum = init;
for x in self {
accum = f(accum, x);
}
accum
它遍历迭代器,将累积的状态传递到闭包中以计算下一个状态。
首先,让我们将类型放在 fold
调用中:
let product = sequence.iter().fold(1, |a: u64, &b: &u8| a * (b as u64));
即我们要的B
类型是u64
(这就是我们最终的产品),迭代器的item类型是&u8
,引用一个字节。
现在,我们可以手动内联 fold
的定义来计算 product
以尝试阐明所需的行为(我现在忽略规范化):
let mut accum = 1;
for x in sequence.iter() {
accum = { // the closure
let a: u64 = accum;
let &b: &u8 = x;
a * b as u64
}
}
let product = accum;
简化:
let mut product = 1;
for &b in sequence.iter() {
product = product * (b as u64)
}
希望这可以使需要发生的事情更清楚:b
遍历每个字节,因此它是需要调整的值,将 ASCII 编码值降低到预期的 0..10 范围.
所以,你是对的:
a * ((b as u64) -b'0')
但是,详细说明编译失败,类型错误:b'0'
has type u8
, but b as u64
as type u64
, and it's not -
与 u64
和 u8
一起使用是合法的。将规范化移动到 u64
演员表之前将确保它正常工作,因为那时你要减去 b
(这是一个 u8
)和一个 u8
:
product * (b - b'0') as u64
总而言之,fold
可能看起来更清晰(并且实际有效):
let product = sequence.iter()
.fold(1, |prod, &byte| prod * (byte - b'0') as u64);
(很抱歉在 IRC 上给了你这么混乱的代码。)
作为 fold
的替代方法,您可以使用 map
and MultiplicativeIterator::product
。我发现这两个步骤有助于更清楚地了解正在发生的事情。
#![feature(core)]
use std::iter::MultiplicativeIterator;
fn main() {
let number = b"123456";
for sequence in number.windows(6) {
let product = sequence.iter().map(|v| (v - b'0') as u64).product();
println!("product of {:?} is {}", sequence, product);
}
}
您甚至可以选择将调整大小从 u8
拆分为 u64
:
sequence.iter().map(|v| v - b'0').map(|v| v as u64).product();
如今,另一种方法是 product
+ to_digit
: (itertools
用于打印迭代器的内容)
use {itertools::Itertools, std::char};
fn main() {
let number = b"123456";
let sequence = number
.iter()
.map(|&c| u64::from(char::from(c).to_digit(10).expect("not a digit")));
let product: u64 = sequence.clone().product();
println!("product of {:?} is {}", sequence.format(", "), product);
}
Running example on play.rust-lang.org
fn main() {
show({
let number = b"123456";
for sequence in number.windows(6) {
let product = sequence.iter().fold(1, |a, &b| a * (b as u64));
println!("product of {:?} is {}", sequence, product);
}
});
}
我不需要像“[49, 50, 51, 52, 53, 54] 的乘积是 15312500000” 这样的输出,我需要括号中的正常数字和乘积的标准化结果。
尝试使用 - b'0'
减去 48 以获得第 5 行中的正常数字不起作用,即
a * ((b as u64) -b'0')
或
(a - b'0') * (b as u64)
似乎我在这里遗漏了一些东西,例如我不知道 fold() 中的 'a' 和 'b' 值到底是什么。谁能启发我? :)
查看the signature of fold
,我们可以看到它有两个参数:
fn fold<B, F>(self, init: B, f: F) -> B
where F: FnMut(B, Self::Item) -> B
init
,它是某种任意类型 B
,和 f
,它是一个闭包,它接受一个 B
值和一个来自迭代器的元素,为了计算一个新的 B
值。整个函数returns一个B
。这些类型强烈暗示发生了什么:闭包 f
在迭代器的连续元素上重复调用,将计算的 B
值传递给下一个 f
调用。检查 the implementation 证实了这个怀疑:
let mut accum = init;
for x in self {
accum = f(accum, x);
}
accum
它遍历迭代器,将累积的状态传递到闭包中以计算下一个状态。
首先,让我们将类型放在 fold
调用中:
let product = sequence.iter().fold(1, |a: u64, &b: &u8| a * (b as u64));
即我们要的B
类型是u64
(这就是我们最终的产品),迭代器的item类型是&u8
,引用一个字节。
现在,我们可以手动内联 fold
的定义来计算 product
以尝试阐明所需的行为(我现在忽略规范化):
let mut accum = 1;
for x in sequence.iter() {
accum = { // the closure
let a: u64 = accum;
let &b: &u8 = x;
a * b as u64
}
}
let product = accum;
简化:
let mut product = 1;
for &b in sequence.iter() {
product = product * (b as u64)
}
希望这可以使需要发生的事情更清楚:b
遍历每个字节,因此它是需要调整的值,将 ASCII 编码值降低到预期的 0..10 范围.
所以,你是对的:
a * ((b as u64) -b'0')
但是,详细说明编译失败,类型错误:b'0'
has type u8
, but b as u64
as type u64
, and it's not -
与 u64
和 u8
一起使用是合法的。将规范化移动到 u64
演员表之前将确保它正常工作,因为那时你要减去 b
(这是一个 u8
)和一个 u8
:
product * (b - b'0') as u64
总而言之,fold
可能看起来更清晰(并且实际有效):
let product = sequence.iter()
.fold(1, |prod, &byte| prod * (byte - b'0') as u64);
(很抱歉在 IRC 上给了你这么混乱的代码。)
作为 fold
的替代方法,您可以使用 map
and MultiplicativeIterator::product
。我发现这两个步骤有助于更清楚地了解正在发生的事情。
#![feature(core)]
use std::iter::MultiplicativeIterator;
fn main() {
let number = b"123456";
for sequence in number.windows(6) {
let product = sequence.iter().map(|v| (v - b'0') as u64).product();
println!("product of {:?} is {}", sequence, product);
}
}
您甚至可以选择将调整大小从 u8
拆分为 u64
:
sequence.iter().map(|v| v - b'0').map(|v| v as u64).product();
如今,另一种方法是 product
+ to_digit
: (itertools
用于打印迭代器的内容)
use {itertools::Itertools, std::char};
fn main() {
let number = b"123456";
let sequence = number
.iter()
.map(|&c| u64::from(char::from(c).to_digit(10).expect("not a digit")));
let product: u64 = sequence.clone().product();
println!("product of {:?} is {}", sequence.format(", "), product);
}