Rust中折叠的问题

时间:2013-12-06 21:04:30

标签: fold rust

我们假设fn scan(int, int) -> int

使用时

fn count(x: int, y: int) -> int
{
    scan(x - 1, y - 1) + scan(x - 1, y) + scan(x - 1, y + 1) + scan(x, y - 1)
        + scan(x, y + 1) + scan(x + 1, y - 1) + scan(x + 1, y) + scan(x + 1, y + 1)
}

我得到了正确的结果。我试图通过fold scan函数在给定的值范围内得到相同的结果;但是,我似乎无法做对。我目前的尝试是

fn count_fold(x: int, y: int) -> int
{
    std::iter::range_inclusive(-1, 1).zip(std::iter::range_inclusive(-1, 1)).fold(0, |a, (i, j)| { a + scan(x + i, y + j) })
}

似乎只返回正确结果的子集。我究竟做错了什么? TIA。

2 个答案:

答案 0 :(得分:5)

当你压缩两个迭代器时,你不是在创建迭代的“产品”,就像你似乎想要做的那样。相反,您同时迭代两个迭代器并使用迭代值创建一对。因此,在count_fold版本中,只会使用以下对调用闭包:

(-1, -1)
(0, 0)
(1, 1)

因此,您的count_fold功能实际上类似于

scan(x - 1, y - 1) + scan(x, y) + scan(x - 1, y + 1)

我可能错了,但我不认为std中有一个函数可以创建两个迭代器的产品。

此外,您的count方法在总和中不使用scan(x, y),因此它甚至不是迭代器的产物;如果你想创建自己的产品迭代器并将其用于此目的,你必须要小心。

答案 1 :(得分:4)

Cyrille说没有迭代器 - 产品功能是正确的。但是,可以通过折叠两次手动获取两个迭代器的乘积:

use std::iter::range_inclusive;

fn count_fold(x: int, y: int) -> int {
    range_inclusive(-1, 1).fold(0, 
         |a, i| range_inclusive(-1, 1).fold(a, |b, j| b + scan(x + i, y + j)))
}

虽然看起来你需要在i == 0 && j == 0时过滤这种情况,即

fn count_fold(x: int, y: int) -> int {
    range_inclusive(-1, 1).fold(0, 
         |a, i| range_inclusive(-1, 1).fold(a, 
             |b, j| if i == 0 && j == 0 {b} else {b + scan(x + i, y + j)}))
}

fn count_fold(x: int, y: int) -> int {
    range_inclusive(-1, 1).fold(0, 
         |a, i| range_inclusive(-1, 1)
             .filter(|&j| !(i == 0 && j == 0))
             .fold(a, |b, j| b + scan(x + i, y + j)))
}

但是,我几乎可以说这更加明确:

fn count_fold(x: int, y: int) -> int {
    let mut a = 0;
    for i in range_inclusive(-1, 1) {
        for j in range_inclusive(-1, 1) {
            if !(i == 0 && j == 0) { a += scan(x + i, y + j) }
        }
    }
    a
}